aboutsummaryrefslogtreecommitdiff
path: root/src/external
diff options
context:
space:
mode:
authorvictorfisac <victorfisac@gmail.com>2017-03-06 09:47:08 +0100
committervictorfisac <victorfisac@gmail.com>2017-03-06 09:47:08 +0100
commitf9277f216372179560c560427beccdd2e5c5d094 (patch)
tree8d3858c978f2b36ea8912f25e3cbe6fa56952aff /src/external
parentce56fcb1eda06385b88c1a906f0968d742ff8130 (diff)
parentc05701253e0a4eda211a0d7ced74ae29d6585917 (diff)
downloadraylib-f9277f216372179560c560427beccdd2e5c5d094.tar.gz
raylib-f9277f216372179560c560427beccdd2e5c5d094.zip
Merge remote-tracking branch 'refs/remotes/raysan5/master'
Diffstat (limited to 'src/external')
-rw-r--r--src/external/OculusSDK/LibOVR/Include/Extras/OVR_CAPI_Util.h196
-rw-r--r--src/external/OculusSDK/LibOVR/Include/Extras/OVR_Math.h3804
-rw-r--r--src/external/OculusSDK/LibOVR/Include/Extras/OVR_StereoProjection.h70
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h2234
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h84
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h158
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h102
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Keys.h53
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h156
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_Version.h60
-rw-r--r--src/external/OculusSDK/LibOVR/LibOVRRT32_1.dllbin0 -> 1044944 bytes
-rw-r--r--src/external/dr_flac.h4564
-rw-r--r--src/external/glad.h5441
-rw-r--r--src/external/glfw3/COPYING.txt22
-rw-r--r--src/external/glfw3/include/GLFW/glfw3.h4235
-rw-r--r--src/external/glfw3/include/GLFW/glfw3native.h456
-rw-r--r--src/external/glfw3/lib/linux/libglfw3.abin0 -> 176482 bytes
-rw-r--r--src/external/glfw3/lib/osx/libglfw.3.0.dylibbin0 -> 127856 bytes
-rw-r--r--src/external/glfw3/lib/osx/libglfw.3.dylib1
-rw-r--r--src/external/glfw3/lib/osx/libglfw.dylib1
-rw-r--r--src/external/glfw3/lib/win32/glfw3.dllbin0 -> 305452 bytes
-rw-r--r--src/external/glfw3/lib/win32/libglfw3.abin0 -> 148800 bytes
-rw-r--r--src/external/glfw3/lib/win32/libglfw3dll.abin0 -> 67426 bytes
-rw-r--r--src/external/jar_mod.h1594
-rw-r--r--src/external/jar_xm.h2664
-rw-r--r--src/external/lua/include/lauxlib.h256
-rw-r--r--src/external/lua/include/lua.h486
-rw-r--r--src/external/lua/include/lua.hpp9
-rw-r--r--src/external/lua/include/luaconf.h769
-rw-r--r--src/external/lua/include/lualib.h58
-rw-r--r--src/external/lua/lib/liblua53.abin0 -> 322424 bytes
-rw-r--r--src/external/lua/lib/liblua53dll.abin0 -> 91416 bytes
-rw-r--r--src/external/openal_soft/COPYING484
-rw-r--r--src/external/openal_soft/include/AL/al.h656
-rw-r--r--src/external/openal_soft/include/AL/alc.h237
-rw-r--r--src/external/openal_soft/include/AL/alext.h443
-rw-r--r--src/external/openal_soft/include/AL/efx-creative.h3
-rw-r--r--src/external/openal_soft/include/AL/efx-presets.h402
-rw-r--r--src/external/openal_soft/include/AL/efx.h761
-rw-r--r--src/external/openal_soft/lib/win32/OpenAL32.dllbin0 -> 845045 bytes
-rw-r--r--src/external/openal_soft/lib/win32/libOpenAL32.abin0 -> 2226842 bytes
-rw-r--r--src/external/openal_soft/lib/win32/libOpenAL32dll.abin0 -> 100246 bytes
-rw-r--r--src/external/pthread/COPYING150
-rw-r--r--src/external/pthread/include/pthread.h1368
-rw-r--r--src/external/pthread/include/sched.h183
-rw-r--r--src/external/pthread/include/semaphore.h169
-rw-r--r--src/external/pthread/lib/libpthreadGC2.abin0 -> 93480 bytes
-rw-r--r--src/external/pthread/lib/pthreadGC2.dllbin0 -> 119888 bytes
-rw-r--r--src/external/stb_image.h7110
-rw-r--r--src/external/stb_image_resize.h2580
-rw-r--r--src/external/stb_image_write.h1049
-rw-r--r--src/external/stb_rect_pack.h583
-rw-r--r--src/external/stb_truetype.h4018
-rw-r--r--src/external/stb_vorbis.c5010
-rw-r--r--src/external/stb_vorbis.h393
-rw-r--r--src/external/tinfl.c592
56 files changed, 53664 insertions, 0 deletions
diff --git a/src/external/OculusSDK/LibOVR/Include/Extras/OVR_CAPI_Util.h b/src/external/OculusSDK/LibOVR/Include/Extras/OVR_CAPI_Util.h
new file mode 100644
index 00000000..552f3b12
--- /dev/null
+++ b/src/external/OculusSDK/LibOVR/Include/Extras/OVR_CAPI_Util.h
@@ -0,0 +1,196 @@
+/********************************************************************************//**
+\file OVR_CAPI_Util.h
+\brief This header provides LibOVR utility function declarations
+\copyright Copyright 2015-2016 Oculus VR, LLC All Rights reserved.
+*************************************************************************************/
+
+#ifndef OVR_CAPI_Util_h
+#define OVR_CAPI_Util_h
+
+
+#include "../OVR_CAPI.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/// Enumerates modifications to the projection matrix based on the application's needs.
+///
+/// \see ovrMatrix4f_Projection
+///
+typedef enum ovrProjectionModifier_
+{
+ /// Use for generating a default projection matrix that is:
+ /// * Right-handed.
+ /// * Near depth values stored in the depth buffer are smaller than far depth values.
+ /// * Both near and far are explicitly defined.
+ /// * With a clipping range that is (0 to w).
+ ovrProjection_None = 0x00,
+
+ /// Enable if using left-handed transformations in your application.
+ ovrProjection_LeftHanded = 0x01,
+
+ /// After the projection transform is applied, far values stored in the depth buffer will be less than closer depth values.
+ /// NOTE: Enable only if the application is using a floating-point depth buffer for proper precision.
+ ovrProjection_FarLessThanNear = 0x02,
+
+ /// When this flag is used, the zfar value pushed into ovrMatrix4f_Projection() will be ignored
+ /// NOTE: Enable only if ovrProjection_FarLessThanNear is also enabled where the far clipping plane will be pushed to infinity.
+ ovrProjection_FarClipAtInfinity = 0x04,
+
+ /// Enable if the application is rendering with OpenGL and expects a projection matrix with a clipping range of (-w to w).
+ /// Ignore this flag if your application already handles the conversion from D3D range (0 to w) to OpenGL.
+ ovrProjection_ClipRangeOpenGL = 0x08,
+} ovrProjectionModifier;
+
+
+/// Return values for ovr_Detect.
+///
+/// \see ovr_Detect
+///
+typedef struct OVR_ALIGNAS(8) ovrDetectResult_
+{
+ /// Is ovrFalse when the Oculus Service is not running.
+ /// This means that the Oculus Service is either uninstalled or stopped.
+ /// IsOculusHMDConnected will be ovrFalse in this case.
+ /// Is ovrTrue when the Oculus Service is running.
+ /// This means that the Oculus Service is installed and running.
+ /// IsOculusHMDConnected will reflect the state of the HMD.
+ ovrBool IsOculusServiceRunning;
+
+ /// Is ovrFalse when an Oculus HMD is not detected.
+ /// If the Oculus Service is not running, this will be ovrFalse.
+ /// Is ovrTrue when an Oculus HMD is detected.
+ /// This implies that the Oculus Service is also installed and running.
+ ovrBool IsOculusHMDConnected;
+
+ OVR_UNUSED_STRUCT_PAD(pad0, 6) ///< \internal struct padding
+
+} ovrDetectResult;
+
+OVR_STATIC_ASSERT(sizeof(ovrDetectResult) == 8, "ovrDetectResult size mismatch");
+
+
+/// Detects Oculus Runtime and Device Status
+///
+/// Checks for Oculus Runtime and Oculus HMD device status without loading the LibOVRRT
+/// shared library. This may be called before ovr_Initialize() to help decide whether or
+/// not to initialize LibOVR.
+///
+/// \param[in] timeoutMilliseconds Specifies a timeout to wait for HMD to be attached or 0 to poll.
+///
+/// \return Returns an ovrDetectResult object indicating the result of detection.
+///
+/// \see ovrDetectResult
+///
+OVR_PUBLIC_FUNCTION(ovrDetectResult) ovr_Detect(int timeoutMilliseconds);
+
+// On the Windows platform,
+#ifdef _WIN32
+ /// This is the Windows Named Event name that is used to check for HMD connected state.
+ #define OVR_HMD_CONNECTED_EVENT_NAME L"OculusHMDConnected"
+#endif // _WIN32
+
+
+/// Used to generate projection from ovrEyeDesc::Fov.
+///
+/// \param[in] fov Specifies the ovrFovPort to use.
+/// \param[in] znear Distance to near Z limit.
+/// \param[in] zfar Distance to far Z limit.
+/// \param[in] projectionModFlags A combination of the ovrProjectionModifier flags.
+///
+/// \return Returns the calculated projection matrix.
+///
+/// \see ovrProjectionModifier
+///
+OVR_PUBLIC_FUNCTION(ovrMatrix4f) ovrMatrix4f_Projection(ovrFovPort fov, float znear, float zfar, unsigned int projectionModFlags);
+
+
+/// Extracts the required data from the result of ovrMatrix4f_Projection.
+///
+/// \param[in] projection Specifies the project matrix from which to extract ovrTimewarpProjectionDesc.
+/// \param[in] projectionModFlags A combination of the ovrProjectionModifier flags.
+/// \return Returns the extracted ovrTimewarpProjectionDesc.
+/// \see ovrTimewarpProjectionDesc
+///
+OVR_PUBLIC_FUNCTION(ovrTimewarpProjectionDesc) ovrTimewarpProjectionDesc_FromProjection(ovrMatrix4f projection, unsigned int projectionModFlags);
+
+
+/// Generates an orthographic sub-projection.
+///
+/// Used for 2D rendering, Y is down.
+///
+/// \param[in] projection The perspective matrix that the orthographic matrix is derived from.
+/// \param[in] orthoScale Equal to 1.0f / pixelsPerTanAngleAtCenter.
+/// \param[in] orthoDistance Equal to the distance from the camera in meters, such as 0.8m.
+/// \param[in] HmdToEyeOffsetX Specifies the offset of the eye from the center.
+///
+/// \return Returns the calculated projection matrix.
+///
+OVR_PUBLIC_FUNCTION(ovrMatrix4f) ovrMatrix4f_OrthoSubProjection(ovrMatrix4f projection, ovrVector2f orthoScale,
+ float orthoDistance, float HmdToEyeOffsetX);
+
+
+
+/// Computes offset eye poses based on headPose returned by ovrTrackingState.
+///
+/// \param[in] headPose Indicates the HMD position and orientation to use for the calculation.
+/// \param[in] hmdToEyeOffset Can be ovrEyeRenderDesc.HmdToEyeOffset returned from
+/// ovr_GetRenderDesc. For monoscopic rendering, use a vector that is the average
+/// of the two vectors for both eyes.
+/// \param[out] outEyePoses If outEyePoses are used for rendering, they should be passed to
+/// ovr_SubmitFrame in ovrLayerEyeFov::RenderPose or ovrLayerEyeFovDepth::RenderPose.
+///
+OVR_PUBLIC_FUNCTION(void) ovr_CalcEyePoses(ovrPosef headPose,
+ const ovrVector3f hmdToEyeOffset[2],
+ ovrPosef outEyePoses[2]);
+
+
+/// Returns the predicted head pose in outHmdTrackingState and offset eye poses in outEyePoses.
+///
+/// This is a thread-safe function where caller should increment frameIndex with every frame
+/// and pass that index where applicable to functions called on the rendering thread.
+/// Assuming outEyePoses are used for rendering, it should be passed as a part of ovrLayerEyeFov.
+/// The caller does not need to worry about applying HmdToEyeOffset to the returned outEyePoses variables.
+///
+/// \param[in] hmd Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] frameIndex Specifies the targeted frame index, or 0 to refer to one frame after
+/// the last time ovr_SubmitFrame was called.
+/// \param[in] latencyMarker Specifies that this call is the point in time where
+/// the "App-to-Mid-Photon" latency timer starts from. If a given ovrLayer
+/// provides "SensorSampleTimestamp", that will override the value stored here.
+/// \param[in] hmdToEyeOffset Can be ovrEyeRenderDesc.HmdToEyeOffset returned from
+/// ovr_GetRenderDesc. For monoscopic rendering, use a vector that is the average
+/// of the two vectors for both eyes.
+/// \param[out] outEyePoses The predicted eye poses.
+/// \param[out] outSensorSampleTime The time when this function was called. May be NULL, in which case it is ignored.
+///
+OVR_PUBLIC_FUNCTION(void) ovr_GetEyePoses(ovrSession session, long long frameIndex, ovrBool latencyMarker,
+ const ovrVector3f hmdToEyeOffset[2],
+ ovrPosef outEyePoses[2],
+ double* outSensorSampleTime);
+
+
+
+/// Tracking poses provided by the SDK come in a right-handed coordinate system. If an application
+/// is passing in ovrProjection_LeftHanded into ovrMatrix4f_Projection, then it should also use
+/// this function to flip the HMD tracking poses to be left-handed.
+///
+/// While this utility function is intended to convert a left-handed ovrPosef into a right-handed
+/// coordinate system, it will also work for converting right-handed to left-handed since the
+/// flip operation is the same for both cases.
+///
+/// \param[in] inPose that is right-handed
+/// \param[out] outPose that is requested to be left-handed (can be the same pointer to inPose)
+///
+OVR_PUBLIC_FUNCTION(void) ovrPosef_FlipHandedness(const ovrPosef* inPose, ovrPosef* outPose);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#endif // Header include guard
diff --git a/src/external/OculusSDK/LibOVR/Include/Extras/OVR_Math.h b/src/external/OculusSDK/LibOVR/Include/Extras/OVR_Math.h
new file mode 100644
index 00000000..89293ff8
--- /dev/null
+++ b/src/external/OculusSDK/LibOVR/Include/Extras/OVR_Math.h
@@ -0,0 +1,3804 @@
+/********************************************************************************//**
+\file OVR_Math.h
+\brief Implementation of 3D primitives such as vectors, matrices.
+\copyright Copyright 2014-2016 Oculus VR, LLC All Rights reserved.
+*************************************************************************************/
+
+#ifndef OVR_Math_h
+#define OVR_Math_h
+
+
+// This file is intended to be independent of the rest of LibOVR and LibOVRKernel and thus
+// has no #include dependencies on either.
+
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <float.h>
+#include "../OVR_CAPI.h" // Currently required due to a dependence on the ovrFovPort_ declaration.
+
+#if defined(_MSC_VER)
+ #pragma warning(push)
+ #pragma warning(disable: 4127) // conditional expression is constant
+#endif
+
+
+#if defined(_MSC_VER)
+ #define OVRMath_sprintf sprintf_s
+#else
+ #define OVRMath_sprintf snprintf
+#endif
+
+
+//-------------------------------------------------------------------------------------
+// ***** OVR_MATH_ASSERT
+//
+// Independent debug break implementation for OVR_Math.h.
+
+#if !defined(OVR_MATH_DEBUG_BREAK)
+ #if defined(_DEBUG)
+ #if defined(_MSC_VER)
+ #define OVR_MATH_DEBUG_BREAK __debugbreak()
+ #else
+ #define OVR_MATH_DEBUG_BREAK __builtin_trap()
+ #endif
+ #else
+ #define OVR_MATH_DEBUG_BREAK ((void)0)
+ #endif
+#endif
+
+
+//-------------------------------------------------------------------------------------
+// ***** OVR_MATH_ASSERT
+//
+// Independent OVR_MATH_ASSERT implementation for OVR_Math.h.
+
+#if !defined(OVR_MATH_ASSERT)
+ #if defined(_DEBUG)
+ #define OVR_MATH_ASSERT(p) if (!(p)) { OVR_MATH_DEBUG_BREAK; }
+ #else
+ #define OVR_MATH_ASSERT(p) ((void)0)
+ #endif
+#endif
+
+
+//-------------------------------------------------------------------------------------
+// ***** OVR_MATH_STATIC_ASSERT
+//
+// Independent OVR_MATH_ASSERT implementation for OVR_Math.h.
+
+#if !defined(OVR_MATH_STATIC_ASSERT)
+ #if defined(__cplusplus) && ((defined(_MSC_VER) && (defined(_MSC_VER) >= 1600)) || defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L))
+ #define OVR_MATH_STATIC_ASSERT static_assert
+ #else
+ #if !defined(OVR_SA_UNUSED)
+ #if defined(__GNUC__) || defined(__clang__)
+ #define OVR_SA_UNUSED __attribute__((unused))
+ #else
+ #define OVR_SA_UNUSED
+ #endif
+ #define OVR_SA_PASTE(a,b) a##b
+ #define OVR_SA_HELP(a,b) OVR_SA_PASTE(a,b)
+ #endif
+
+ #define OVR_MATH_STATIC_ASSERT(expression, msg) typedef char OVR_SA_HELP(compileTimeAssert, __LINE__) [((expression) != 0) ? 1 : -1] OVR_SA_UNUSED
+ #endif
+#endif
+
+
+
+namespace OVR {
+
+template<class T>
+const T OVRMath_Min(const T a, const T b)
+{ return (a < b) ? a : b; }
+
+template<class T>
+const T OVRMath_Max(const T a, const T b)
+{ return (b < a) ? a : b; }
+
+template<class T>
+void OVRMath_Swap(T& a, T& b)
+{ T temp(a); a = b; b = temp; }
+
+
+//-------------------------------------------------------------------------------------
+// ***** Constants for 3D world/axis definitions.
+
+// Definitions of axes for coordinate and rotation conversions.
+enum Axis
+{
+ Axis_X = 0, Axis_Y = 1, Axis_Z = 2
+};
+
+// RotateDirection describes the rotation direction around an axis, interpreted as follows:
+// CW - Clockwise while looking "down" from positive axis towards the origin.
+// CCW - Counter-clockwise while looking from the positive axis towards the origin,
+// which is in the negative axis direction.
+// CCW is the default for the RHS coordinate system. Oculus standard RHS coordinate
+// system defines Y up, X right, and Z back (pointing out from the screen). In this
+// system Rotate_CCW around Z will specifies counter-clockwise rotation in XY plane.
+enum RotateDirection
+{
+ Rotate_CCW = 1,
+ Rotate_CW = -1
+};
+
+// Constants for right handed and left handed coordinate systems
+enum HandedSystem
+{
+ Handed_R = 1, Handed_L = -1
+};
+
+// AxisDirection describes which way the coordinate axis points. Used by WorldAxes.
+enum AxisDirection
+{
+ Axis_Up = 2,
+ Axis_Down = -2,
+ Axis_Right = 1,
+ Axis_Left = -1,
+ Axis_In = 3,
+ Axis_Out = -3
+};
+
+struct WorldAxes
+{
+ AxisDirection XAxis, YAxis, ZAxis;
+
+ WorldAxes(AxisDirection x, AxisDirection y, AxisDirection z)
+ : XAxis(x), YAxis(y), ZAxis(z)
+ { OVR_MATH_ASSERT(abs(x) != abs(y) && abs(y) != abs(z) && abs(z) != abs(x));}
+};
+
+} // namespace OVR
+
+
+//------------------------------------------------------------------------------------//
+// ***** C Compatibility Types
+
+// These declarations are used to support conversion between C types used in
+// LibOVR C interfaces and their C++ versions. As an example, they allow passing
+// Vector3f into a function that expects ovrVector3f.
+
+typedef struct ovrQuatf_ ovrQuatf;
+typedef struct ovrQuatd_ ovrQuatd;
+typedef struct ovrSizei_ ovrSizei;
+typedef struct ovrSizef_ ovrSizef;
+typedef struct ovrSized_ ovrSized;
+typedef struct ovrRecti_ ovrRecti;
+typedef struct ovrVector2i_ ovrVector2i;
+typedef struct ovrVector2f_ ovrVector2f;
+typedef struct ovrVector2d_ ovrVector2d;
+typedef struct ovrVector3f_ ovrVector3f;
+typedef struct ovrVector3d_ ovrVector3d;
+typedef struct ovrVector4f_ ovrVector4f;
+typedef struct ovrVector4d_ ovrVector4d;
+typedef struct ovrMatrix2f_ ovrMatrix2f;
+typedef struct ovrMatrix2d_ ovrMatrix2d;
+typedef struct ovrMatrix3f_ ovrMatrix3f;
+typedef struct ovrMatrix3d_ ovrMatrix3d;
+typedef struct ovrMatrix4f_ ovrMatrix4f;
+typedef struct ovrMatrix4d_ ovrMatrix4d;
+typedef struct ovrPosef_ ovrPosef;
+typedef struct ovrPosed_ ovrPosed;
+typedef struct ovrPoseStatef_ ovrPoseStatef;
+typedef struct ovrPoseStated_ ovrPoseStated;
+
+namespace OVR {
+
+// Forward-declare our templates.
+template<class T> class Quat;
+template<class T> class Size;
+template<class T> class Rect;
+template<class T> class Vector2;
+template<class T> class Vector3;
+template<class T> class Vector4;
+template<class T> class Matrix2;
+template<class T> class Matrix3;
+template<class T> class Matrix4;
+template<class T> class Pose;
+template<class T> class PoseState;
+
+// CompatibleTypes::Type is used to lookup a compatible C-version of a C++ class.
+template<class C>
+struct CompatibleTypes
+{
+ // Declaration here seems necessary for MSVC; specializations are
+ // used instead.
+ typedef struct {} Type;
+};
+
+// Specializations providing CompatibleTypes::Type value.
+template<> struct CompatibleTypes<Quat<float> > { typedef ovrQuatf Type; };
+template<> struct CompatibleTypes<Quat<double> > { typedef ovrQuatd Type; };
+template<> struct CompatibleTypes<Matrix2<float> > { typedef ovrMatrix2f Type; };
+template<> struct CompatibleTypes<Matrix2<double> > { typedef ovrMatrix2d Type; };
+template<> struct CompatibleTypes<Matrix3<float> > { typedef ovrMatrix3f Type; };
+template<> struct CompatibleTypes<Matrix3<double> > { typedef ovrMatrix3d Type; };
+template<> struct CompatibleTypes<Matrix4<float> > { typedef ovrMatrix4f Type; };
+template<> struct CompatibleTypes<Matrix4<double> > { typedef ovrMatrix4d Type; };
+template<> struct CompatibleTypes<Size<int> > { typedef ovrSizei Type; };
+template<> struct CompatibleTypes<Size<float> > { typedef ovrSizef Type; };
+template<> struct CompatibleTypes<Size<double> > { typedef ovrSized Type; };
+template<> struct CompatibleTypes<Rect<int> > { typedef ovrRecti Type; };
+template<> struct CompatibleTypes<Vector2<int> > { typedef ovrVector2i Type; };
+template<> struct CompatibleTypes<Vector2<float> > { typedef ovrVector2f Type; };
+template<> struct CompatibleTypes<Vector2<double> > { typedef ovrVector2d Type; };
+template<> struct CompatibleTypes<Vector3<float> > { typedef ovrVector3f Type; };
+template<> struct CompatibleTypes<Vector3<double> > { typedef ovrVector3d Type; };
+template<> struct CompatibleTypes<Vector4<float> > { typedef ovrVector4f Type; };
+template<> struct CompatibleTypes<Vector4<double> > { typedef ovrVector4d Type; };
+template<> struct CompatibleTypes<Pose<float> > { typedef ovrPosef Type; };
+template<> struct CompatibleTypes<Pose<double> > { typedef ovrPosed Type; };
+
+//------------------------------------------------------------------------------------//
+// ***** Math
+//
+// Math class contains constants and functions. This class is a template specialized
+// per type, with Math<float> and Math<double> being distinct.
+template<class T>
+class Math
+{
+public:
+ // By default, support explicit conversion to float. This allows Vector2<int> to
+ // compile, for example.
+ typedef float OtherFloatType;
+
+ static int Tolerance() { return 0; } // Default value so integer types compile
+};
+
+
+//------------------------------------------------------------------------------------//
+// ***** double constants
+#define MATH_DOUBLE_PI 3.14159265358979323846
+#define MATH_DOUBLE_TWOPI (2*MATH_DOUBLE_PI)
+#define MATH_DOUBLE_PIOVER2 (0.5*MATH_DOUBLE_PI)
+#define MATH_DOUBLE_PIOVER4 (0.25*MATH_DOUBLE_PI)
+#define MATH_FLOAT_MAXVALUE (FLT_MAX)
+
+#define MATH_DOUBLE_RADTODEGREEFACTOR (360.0 / MATH_DOUBLE_TWOPI)
+#define MATH_DOUBLE_DEGREETORADFACTOR (MATH_DOUBLE_TWOPI / 360.0)
+
+#define MATH_DOUBLE_E 2.71828182845904523536
+#define MATH_DOUBLE_LOG2E 1.44269504088896340736
+#define MATH_DOUBLE_LOG10E 0.434294481903251827651
+#define MATH_DOUBLE_LN2 0.693147180559945309417
+#define MATH_DOUBLE_LN10 2.30258509299404568402
+
+#define MATH_DOUBLE_SQRT2 1.41421356237309504880
+#define MATH_DOUBLE_SQRT1_2 0.707106781186547524401
+
+#define MATH_DOUBLE_TOLERANCE 1e-12 // a default number for value equality tolerance: about 4500*Epsilon;
+#define MATH_DOUBLE_SINGULARITYRADIUS 1e-12 // about 1-cos(.0001 degree), for gimbal lock numerical problems
+
+//------------------------------------------------------------------------------------//
+// ***** float constants
+#define MATH_FLOAT_PI float(MATH_DOUBLE_PI)
+#define MATH_FLOAT_TWOPI float(MATH_DOUBLE_TWOPI)
+#define MATH_FLOAT_PIOVER2 float(MATH_DOUBLE_PIOVER2)
+#define MATH_FLOAT_PIOVER4 float(MATH_DOUBLE_PIOVER4)
+
+#define MATH_FLOAT_RADTODEGREEFACTOR float(MATH_DOUBLE_RADTODEGREEFACTOR)
+#define MATH_FLOAT_DEGREETORADFACTOR float(MATH_DOUBLE_DEGREETORADFACTOR)
+
+#define MATH_FLOAT_E float(MATH_DOUBLE_E)
+#define MATH_FLOAT_LOG2E float(MATH_DOUBLE_LOG2E)
+#define MATH_FLOAT_LOG10E float(MATH_DOUBLE_LOG10E)
+#define MATH_FLOAT_LN2 float(MATH_DOUBLE_LN2)
+#define MATH_FLOAT_LN10 float(MATH_DOUBLE_LN10)
+
+#define MATH_FLOAT_SQRT2 float(MATH_DOUBLE_SQRT2)
+#define MATH_FLOAT_SQRT1_2 float(MATH_DOUBLE_SQRT1_2)
+
+#define MATH_FLOAT_TOLERANCE 1e-5f // a default number for value equality tolerance: 1e-5, about 84*EPSILON;
+#define MATH_FLOAT_SINGULARITYRADIUS 1e-7f // about 1-cos(.025 degree), for gimbal lock numerical problems
+
+
+
+// Single-precision Math constants class.
+template<>
+class Math<float>
+{
+public:
+ typedef double OtherFloatType;
+
+ static inline float Tolerance() { return MATH_FLOAT_TOLERANCE; }; // a default number for value equality tolerance
+ static inline float SingularityRadius() { return MATH_FLOAT_SINGULARITYRADIUS; }; // for gimbal lock numerical problems
+};
+
+// Double-precision Math constants class
+template<>
+class Math<double>
+{
+public:
+ typedef float OtherFloatType;
+
+ static inline double Tolerance() { return MATH_DOUBLE_TOLERANCE; }; // a default number for value equality tolerance
+ static inline double SingularityRadius() { return MATH_DOUBLE_SINGULARITYRADIUS; }; // for gimbal lock numerical problems
+};
+
+typedef Math<float> Mathf;
+typedef Math<double> Mathd;
+
+// Conversion functions between degrees and radians
+// (non-templated to ensure passing int arguments causes warning)
+inline float RadToDegree(float rad) { return rad * MATH_FLOAT_RADTODEGREEFACTOR; }
+inline double RadToDegree(double rad) { return rad * MATH_DOUBLE_RADTODEGREEFACTOR; }
+
+inline float DegreeToRad(float deg) { return deg * MATH_FLOAT_DEGREETORADFACTOR; }
+inline double DegreeToRad(double deg) { return deg * MATH_DOUBLE_DEGREETORADFACTOR; }
+
+// Square function
+template<class T>
+inline T Sqr(T x) { return x*x; }
+
+// Sign: returns 0 if x == 0, -1 if x < 0, and 1 if x > 0
+template<class T>
+inline T Sign(T x) { return (x != T(0)) ? (x < T(0) ? T(-1) : T(1)) : T(0); }
+
+// Numerically stable acos function
+inline float Acos(float x) { return (x > 1.0f) ? 0.0f : (x < -1.0f) ? MATH_FLOAT_PI : acosf(x); }
+inline double Acos(double x) { return (x > 1.0) ? 0.0 : (x < -1.0) ? MATH_DOUBLE_PI : acos(x); }
+
+// Numerically stable asin function
+inline float Asin(float x) { return (x > 1.0f) ? MATH_FLOAT_PIOVER2 : (x < -1.0f) ? -MATH_FLOAT_PIOVER2 : asinf(x); }
+inline double Asin(double x) { return (x > 1.0) ? MATH_DOUBLE_PIOVER2 : (x < -1.0) ? -MATH_DOUBLE_PIOVER2 : asin(x); }
+
+#if defined(_MSC_VER)
+ inline int isnan(double x) { return ::_isnan(x); }
+#elif !defined(isnan) // Some libraries #define isnan.
+ inline int isnan(double x) { return ::isnan(x); }
+#endif
+
+template<class T>
+class Quat;
+
+
+//-------------------------------------------------------------------------------------
+// ***** Vector2<>
+
+// Vector2f (Vector2d) represents a 2-dimensional vector or point in space,
+// consisting of coordinates x and y
+
+template<class T>
+class Vector2
+{
+public:
+ typedef T ElementType;
+ static const size_t ElementCount = 2;
+
+ T x, y;
+
+ Vector2() : x(0), y(0) { }
+ Vector2(T x_, T y_) : x(x_), y(y_) { }
+ explicit Vector2(T s) : x(s), y(s) { }
+ explicit Vector2(const Vector2<typename Math<T>::OtherFloatType> &src)
+ : x((T)src.x), y((T)src.y) { }
+
+ static Vector2 Zero() { return Vector2(0, 0); }
+
+ // C-interop support.
+ typedef typename CompatibleTypes<Vector2<T> >::Type CompatibleType;
+
+ Vector2(const CompatibleType& s) : x(s.x), y(s.y) { }
+
+ operator const CompatibleType& () const
+ {
+ OVR_MATH_STATIC_ASSERT(sizeof(Vector2<T>) == sizeof(CompatibleType), "sizeof(Vector2<T>) failure");
+ return reinterpret_cast<const CompatibleType&>(*this);
+ }
+
+
+ bool operator== (const Vector2& b) const { return x == b.x && y == b.y; }
+ bool operator!= (const Vector2& b) const { return x != b.x || y != b.y; }
+
+ Vector2 operator+ (const Vector2& b) const { return Vector2(x + b.x, y + b.y); }
+ Vector2& operator+= (const Vector2& b) { x += b.x; y += b.y; return *this; }
+ Vector2 operator- (const Vector2& b) const { return Vector2(x - b.x, y - b.y); }
+ Vector2& operator-= (const Vector2& b) { x -= b.x; y -= b.y; return *this; }
+ Vector2 operator- () const { return Vector2(-x, -y); }
+
+ // Scalar multiplication/division scales vector.
+ Vector2 operator* (T s) const { return Vector2(x*s, y*s); }
+ Vector2& operator*= (T s) { x *= s; y *= s; return *this; }
+
+ Vector2 operator/ (T s) const { T rcp = T(1)/s;
+ return Vector2(x*rcp, y*rcp); }
+ Vector2& operator/= (T s) { T rcp = T(1)/s;
+ x *= rcp; y *= rcp;
+ return *this; }
+
+ static Vector2 Min(const Vector2& a, const Vector2& b) { return Vector2((a.x < b.x) ? a.x : b.x,
+ (a.y < b.y) ? a.y : b.y); }
+ static Vector2 Max(const Vector2& a, const Vector2& b) { return Vector2((a.x > b.x) ? a.x : b.x,
+ (a.y > b.y) ? a.y : b.y); }
+
+ Vector2 Clamped(T maxMag) const
+ {
+ T magSquared = LengthSq();
+ if (magSquared <= Sqr(maxMag))
+ return *this;
+ else
+ return *this * (maxMag / sqrt(magSquared));
+ }
+
+ // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance.
+ bool IsEqual(const Vector2& b, T tolerance =Math<T>::Tolerance()) const
+ {
+ return (fabs(b.x-x) <= tolerance) &&
+ (fabs(b.y-y) <= tolerance);
+ }
+ bool Compare(const Vector2& b, T tolerance = Math<T>::Tolerance()) const
+ {
+ return IsEqual(b, tolerance);
+ }
+
+ // Access element by index
+ T& operator[] (int idx)
+ {
+ OVR_MATH_ASSERT(0 <= idx && idx < 2);
+ return *(&x + idx);
+ }
+ const T& operator[] (int idx) const
+ {
+ OVR_MATH_ASSERT(0 <= idx && idx < 2);
+ return *(&x + idx);
+ }
+
+ // Entry-wise product of two vectors
+ Vector2 EntrywiseMultiply(const Vector2& b) const { return Vector2(x * b.x, y * b.y);}
+
+
+ // Multiply and divide operators do entry-wise math. Used Dot() for dot product.
+ Vector2 operator* (const Vector2& b) const { return Vector2(x * b.x, y * b.y); }
+ Vector2 operator/ (const Vector2& b) const { return Vector2(x / b.x, y / b.y); }
+
+ // Dot product
+ // Used to calculate angle q between two vectors among other things,
+ // as (A dot B) = |a||b|cos(q).
+ T Dot(const Vector2& b) const { return x*b.x + y*b.y; }
+
+ // Returns the angle from this vector to b, in radians.
+ T Angle(const Vector2& b) const
+ {
+ T div = LengthSq()*b.LengthSq();
+ OVR_MATH_ASSERT(div != T(0));
+ T result = Acos((this->Dot(b))/sqrt(div));
+ return result;
+ }
+
+ // Return Length of the vector squared.
+ T LengthSq() const { return (x * x + y * y); }
+
+ // Return vector length.
+ T Length() const { return sqrt(LengthSq()); }
+
+ // Returns squared distance between two points represented by vectors.
+ T DistanceSq(const Vector2& b) const { return (*this - b).LengthSq(); }
+
+ // Returns distance between two points represented by vectors.
+ T Distance(const Vector2& b) const { return (*this - b).Length(); }
+
+ // Determine if this a unit vector.
+ bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance(); }
+
+ // Normalize, convention vector length to 1.
+ void Normalize()
+ {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ *this *= s;
+ }
+
+ // Returns normalized (unit) version of the vector without modifying itself.
+ Vector2 Normalized() const
+ {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ return *this * s;
+ }
+
+ // Linearly interpolates from this vector to another.
+ // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
+ Vector2 Lerp(const Vector2& b, T f) const { return *this*(T(1) - f) + b*f; }
+
+ // Projects this vector onto the argument; in other words,
+ // A.Project(B) returns projection of vector A onto B.
+ Vector2 ProjectTo(const Vector2& b) const
+ {
+ T l2 = b.LengthSq();
+ OVR_MATH_ASSERT(l2 != T(0));
+ return b * ( Dot(b) / l2 );
+ }
+
+ // returns true if vector b is clockwise from this vector
+ bool IsClockwise(const Vector2& b) const
+ {
+ return (x * b.y - y * b.x) < 0;
+ }
+};
+
+
+typedef Vector2<float> Vector2f;
+typedef Vector2<double> Vector2d;
+typedef Vector2<int> Vector2i;
+
+typedef Vector2<float> Point2f;
+typedef Vector2<double> Point2d;
+typedef Vector2<int> Point2i;
+
+//-------------------------------------------------------------------------------------
+// ***** Vector3<> - 3D vector of {x, y, z}
+
+//
+// Vector3f (Vector3d) represents a 3-dimensional vector or point in space,
+// consisting of coordinates x, y and z.
+
+template<class T>
+class Vector3
+{
+public:
+ typedef T ElementType;
+ static const size_t ElementCount = 3;
+
+ T x, y, z;
+
+ // FIXME: default initialization of a vector class can be very expensive in a full-blown
+ // application. A few hundred thousand vector constructions is not unlikely and can add
+ // up to milliseconds of time on processors like the PS3 PPU.
+ Vector3() : x(0), y(0), z(0) { }
+ Vector3(T x_, T y_, T z_ = 0) : x(x_), y(y_), z(z_) { }
+ explicit Vector3(T s) : x(s), y(s), z(s) { }
+ explicit Vector3(const Vector3<typename Math<T>::OtherFloatType> &src)
+ : x((T)src.x), y((T)src.y), z((T)src.z) { }
+
+ static Vector3 Zero() { return Vector3(0, 0, 0); }
+
+ // C-interop support.
+ typedef typename CompatibleTypes<Vector3<T> >::Type CompatibleType;
+
+ Vector3(const CompatibleType& s) : x(s.x), y(s.y), z(s.z) { }
+
+ operator const CompatibleType& () const
+ {
+ OVR_MATH_STATIC_ASSERT(sizeof(Vector3<T>) == sizeof(CompatibleType), "sizeof(Vector3<T>) failure");
+ return reinterpret_cast<const CompatibleType&>(*this);
+ }
+
+ bool operator== (const Vector3& b) const { return x == b.x && y == b.y && z == b.z; }
+ bool operator!= (const Vector3& b) const { return x != b.x || y != b.y || z != b.z; }
+
+ Vector3 operator+ (const Vector3& b) const { return Vector3(x + b.x, y + b.y, z + b.z); }
+ Vector3& operator+= (const Vector3& b) { x += b.x; y += b.y; z += b.z; return *this; }
+ Vector3 operator- (const Vector3& b) const { return Vector3(x - b.x, y - b.y, z - b.z); }
+ Vector3& operator-= (const Vector3& b) { x -= b.x; y -= b.y; z -= b.z; return *this; }
+ Vector3 operator- () const { return Vector3(-x, -y, -z); }
+
+ // Scalar multiplication/division scales vector.
+ Vector3 operator* (T s) const { return Vector3(x*s, y*s, z*s); }
+ Vector3& operator*= (T s) { x *= s; y *= s; z *= s; return *this; }
+
+ Vector3 operator/ (T s) const { T rcp = T(1)/s;
+ return Vector3(x*rcp, y*rcp, z*rcp); }
+ Vector3& operator/= (T s) { T rcp = T(1)/s;
+ x *= rcp; y *= rcp; z *= rcp;
+ return *this; }
+
+ static Vector3 Min(const Vector3& a, const Vector3& b)
+ {
+ return Vector3((a.x < b.x) ? a.x : b.x,
+ (a.y < b.y) ? a.y : b.y,
+ (a.z < b.z) ? a.z : b.z);
+ }
+ static Vector3 Max(const Vector3& a, const Vector3& b)
+ {
+ return Vector3((a.x > b.x) ? a.x : b.x,
+ (a.y > b.y) ? a.y : b.y,
+ (a.z > b.z) ? a.z : b.z);
+ }
+
+ Vector3 Clamped(T maxMag) const
+ {
+ T magSquared = LengthSq();
+ if (magSquared <= Sqr(maxMag))
+ return *this;
+ else
+ return *this * (maxMag / sqrt(magSquared));
+ }
+
+ // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance.
+ bool IsEqual(const Vector3& b, T tolerance = Math<T>::Tolerance()) const
+ {
+ return (fabs(b.x-x) <= tolerance) &&
+ (fabs(b.y-y) <= tolerance) &&
+ (fabs(b.z-z) <= tolerance);
+ }
+ bool Compare(const Vector3& b, T tolerance = Math<T>::Tolerance()) const
+ {
+ return IsEqual(b, tolerance);
+ }
+
+ T& operator[] (int idx)
+ {
+ OVR_MATH_ASSERT(0 <= idx && idx < 3);
+ return *(&x + idx);
+ }
+
+ const T& operator[] (int idx) const
+ {
+ OVR_MATH_ASSERT(0 <= idx && idx < 3);
+ return *(&x + idx);
+ }
+
+ // Entrywise product of two vectors
+ Vector3 EntrywiseMultiply(const Vector3& b) const { return Vector3(x * b.x,
+ y * b.y,
+ z * b.z);}
+
+ // Multiply and divide operators do entry-wise math
+ Vector3 operator* (const Vector3& b) const { return Vector3(x * b.x,
+ y * b.y,
+ z * b.z); }
+
+ Vector3 operator/ (const Vector3& b) const { return Vector3(x / b.x,
+ y / b.y,
+ z / b.z); }
+
+
+ // Dot product
+ // Used to calculate angle q between two vectors among other things,
+ // as (A dot B) = |a||b|cos(q).
+ T Dot(const Vector3& b) const { return x*b.x + y*b.y + z*b.z; }
+
+ // Compute cross product, which generates a normal vector.
+ // Direction vector can be determined by right-hand rule: Pointing index finder in
+ // direction a and middle finger in direction b, thumb will point in a.Cross(b).
+ Vector3 Cross(const Vector3& b) const { return Vector3(y*b.z - z*b.y,
+ z*b.x - x*b.z,
+ x*b.y - y*b.x); }
+
+ // Returns the angle from this vector to b, in radians.
+ T Angle(const Vector3& b) const
+ {
+ T div = LengthSq()*b.LengthSq();
+ OVR_MATH_ASSERT(div != T(0));
+ T result = Acos((this->Dot(b))/sqrt(div));
+ return result;
+ }
+
+ // Return Length of the vector squared.
+ T LengthSq() const { return (x * x + y * y + z * z); }
+
+ // Return vector length.
+ T Length() const { return (T)sqrt(LengthSq()); }
+
+ // Returns squared distance between two points represented by vectors.
+ T DistanceSq(Vector3 const& b) const { return (*this - b).LengthSq(); }
+
+ // Returns distance between two points represented by vectors.
+ T Distance(Vector3 const& b) const { return (*this - b).Length(); }
+
+ bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance(); }
+
+ // Normalize, convention vector length to 1.
+ void Normalize()
+ {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ *this *= s;
+ }
+
+ // Returns normalized (unit) version of the vector without modifying itself.
+ Vector3 Normalized() const
+ {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ return *this * s;
+ }
+
+ // Linearly interpolates from this vector to another.
+ // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
+ Vector3 Lerp(const Vector3& b, T f) const { return *this*(T(1) - f) + b*f; }
+
+ // Projects this vector onto the argument; in other words,
+ // A.Project(B) returns projection of vector A onto B.
+ Vector3 ProjectTo(const Vector3& b) const
+ {
+ T l2 = b.LengthSq();
+ OVR_MATH_ASSERT(l2 != T(0));
+ return b * ( Dot(b) / l2 );
+ }
+
+ // Projects this vector onto a plane defined by a normal vector
+ Vector3 ProjectToPlane(const Vector3& normal) const { return *this - this->ProjectTo(normal); }
+};
+
+typedef Vector3<float> Vector3f;
+typedef Vector3<double> Vector3d;
+typedef Vector3<int32_t> Vector3i;
+
+OVR_MATH_STATIC_ASSERT((sizeof(Vector3f) == 3*sizeof(float)), "sizeof(Vector3f) failure");
+OVR_MATH_STATIC_ASSERT((sizeof(Vector3d) == 3*sizeof(double)), "sizeof(Vector3d) failure");
+OVR_MATH_STATIC_ASSERT((sizeof(Vector3i) == 3*sizeof(int32_t)), "sizeof(Vector3i) failure");
+
+typedef Vector3<float> Point3f;
+typedef Vector3<double> Point3d;
+typedef Vector3<int32_t> Point3i;
+
+
+//-------------------------------------------------------------------------------------
+// ***** Vector4<> - 4D vector of {x, y, z, w}
+
+//
+// Vector4f (Vector4d) represents a 3-dimensional vector or point in space,
+// consisting of coordinates x, y, z and w.
+
+template<class T>
+class Vector4
+{
+public:
+ typedef T ElementType;
+ static const size_t ElementCount = 4;
+
+ T x, y, z, w;
+
+ // FIXME: default initialization of a vector class can be very expensive in a full-blown
+ // application. A few hundred thousand vector constructions is not unlikely and can add
+ // up to milliseconds of time on processors like the PS3 PPU.
+ Vector4() : x(0), y(0), z(0), w(0) { }
+ Vector4(T x_, T y_, T z_, T w_) : x(x_), y(y_), z(z_), w(w_) { }
+ explicit Vector4(T s) : x(s), y(s), z(s), w(s) { }
+ explicit Vector4(const Vector3<T>& v, const T w_=T(1)) : x(v.x), y(v.y), z(v.z), w(w_) { }
+ explicit Vector4(const Vector4<typename Math<T>::OtherFloatType> &src)
+ : x((T)src.x), y((T)src.y), z((T)src.z), w((T)src.w) { }
+
+ static Vector4 Zero() { return Vector4(0, 0, 0, 0); }
+
+ // C-interop support.
+ typedef typename CompatibleTypes< Vector4<T> >::Type CompatibleType;
+
+ Vector4(const CompatibleType& s) : x(s.x), y(s.y), z(s.z), w(s.w) { }
+
+ operator const CompatibleType& () const
+ {
+ OVR_MATH_STATIC_ASSERT(sizeof(Vector4<T>) == sizeof(CompatibleType), "sizeof(Vector4<T>) failure");
+ return reinterpret_cast<const CompatibleType&>(*this);
+ }
+
+ Vector4& operator= (const Vector3<T>& other) { x=other.x; y=other.y; z=other.z; w=1; return *this; }
+ bool operator== (const Vector4& b) const { return x == b.x && y == b.y && z == b.z && w == b.w; }
+ bool operator!= (const Vector4& b) const { return x != b.x || y != b.y || z != b.z || w != b.w; }
+
+ Vector4 operator+ (const Vector4& b) const { return Vector4(x + b.x, y + b.y, z + b.z, w + b.w); }
+ Vector4& operator+= (const Vector4& b) { x += b.x; y += b.y; z += b.z; w += b.w; return *this; }
+ Vector4 operator- (const Vector4& b) const { return Vector4(x - b.x, y - b.y, z - b.z, w - b.w); }
+ Vector4& operator-= (const Vector4& b) { x -= b.x; y -= b.y; z -= b.z; w -= b.w; return *this; }
+ Vector4 operator- () const { return Vector4(-x, -y, -z, -w); }
+
+ // Scalar multiplication/division scales vector.
+ Vector4 operator* (T s) const { return Vector4(x*s, y*s, z*s, w*s); }
+ Vector4& operator*= (T s) { x *= s; y *= s; z *= s; w *= s;return *this; }
+
+ Vector4 operator/ (T s) const { T rcp = T(1)/s;
+ return Vector4(x*rcp, y*rcp, z*rcp, w*rcp); }
+ Vector4& operator/= (T s) { T rcp = T(1)/s;
+ x *= rcp; y *= rcp; z *= rcp; w *= rcp;
+ return *this; }
+
+ static Vector4 Min(const Vector4& a, const Vector4& b)
+ {
+ return Vector4((a.x < b.x) ? a.x : b.x,
+ (a.y < b.y) ? a.y : b.y,
+ (a.z < b.z) ? a.z : b.z,
+ (a.w < b.w) ? a.w : b.w);
+ }
+ static Vector4 Max(const Vector4& a, const Vector4& b)
+ {
+ return Vector4((a.x > b.x) ? a.x : b.x,
+ (a.y > b.y) ? a.y : b.y,
+ (a.z > b.z) ? a.z : b.z,
+ (a.w > b.w) ? a.w : b.w);
+ }
+
+ Vector4 Clamped(T maxMag) const
+ {
+ T magSquared = LengthSq();
+ if (magSquared <= Sqr(maxMag))
+ return *this;
+ else
+ return *this * (maxMag / sqrt(magSquared));
+ }
+
+ // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance.
+ bool IsEqual(const Vector4& b, T tolerance = Math<T>::Tolerance()) const
+ {
+ return (fabs(b.x-x) <= tolerance) &&
+ (fabs(b.y-y) <= tolerance) &&
+ (fabs(b.z-z) <= tolerance) &&
+ (fabs(b.w-w) <= tolerance);
+ }
+ bool Compare(const Vector4& b, T tolerance = Math<T>::Tolerance()) const
+ {
+ return IsEqual(b, tolerance);
+ }
+
+ T& operator[] (int idx)
+ {
+ OVR_MATH_ASSERT(0 <= idx && idx < 4);
+ return *(&x + idx);
+ }
+
+ const T& operator[] (int idx) const
+ {
+ OVR_MATH_ASSERT(0 <= idx && idx < 4);
+ return *(&x + idx);
+ }
+
+ // Entry wise product of two vectors
+ Vector4 EntrywiseMultiply(const Vector4& b) const { return Vector4(x * b.x,
+ y * b.y,
+ z * b.z,
+ w * b.w);}
+
+ // Multiply and divide operators do entry-wise math
+ Vector4 operator* (const Vector4& b) const { return Vector4(x * b.x,
+ y * b.y,
+ z * b.z,
+ w * b.w); }
+
+ Vector4 operator/ (const Vector4& b) const { return Vector4(x / b.x,
+ y / b.y,
+ z / b.z,
+ w / b.w); }
+
+
+ // Dot product
+ T Dot(const Vector4& b) const { return x*b.x + y*b.y + z*b.z + w*b.w; }
+
+ // Return Length of the vector squared.
+ T LengthSq() const { return (x * x + y * y + z * z + w * w); }
+
+ // Return vector length.
+ T Length() const { return sqrt(LengthSq()); }
+
+ bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance(); }
+
+ // Normalize, convention vector length to 1.
+ void Normalize()
+ {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ *this *= s;
+ }
+
+ // Returns normalized (unit) version of the vector without modifying itself.
+ Vector4 Normalized() const
+ {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ return *this * s;
+ }
+
+ // Linearly interpolates from this vector to another.
+ // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
+ Vector4 Lerp(const Vector4& b, T f) const { return *this*(T(1) - f) + b*f; }
+};
+
+typedef Vector4<float> Vector4f;
+typedef Vector4<double> Vector4d;
+typedef Vector4<int> Vector4i;
+
+
+//-------------------------------------------------------------------------------------
+// ***** Bounds3
+
+// Bounds class used to describe a 3D axis aligned bounding box.
+
+template<class T>
+class Bounds3
+{
+public:
+ Vector3<T> b[2];
+
+ Bounds3()
+ {
+ }
+
+ Bounds3( const Vector3<T> & mins, const Vector3<T> & maxs )
+{
+ b[0] = mins;
+ b[1] = maxs;
+ }
+
+ void Clear()
+ {
+ b[0].x = b[0].y = b[0].z = Math<T>::MaxValue;
+ b[1].x = b[1].y = b[1].z = -Math<T>::MaxValue;
+ }
+
+ void AddPoint( const Vector3<T> & v )
+ {
+ b[0].x = (b[0].x < v.x ? b[0].x : v.x);
+ b[0].y = (b[0].y < v.y ? b[0].y : v.y);
+ b[0].z = (b[0].z < v.z ? b[0].z : v.z);
+ b[1].x = (v.x < b[1].x ? b[1].x : v.x);
+ b[1].y = (v.y < b[1].y ? b[1].y : v.y);
+ b[1].z = (v.z < b[1].z ? b[1].z : v.z);
+ }
+
+ const Vector3<T> & GetMins() const { return b[0]; }
+ const Vector3<T> & GetMaxs() const { return b[1]; }
+
+ Vector3<T> & GetMins() { return b[0]; }
+ Vector3<T> & GetMaxs() { return b[1]; }
+};
+
+typedef Bounds3<float> Bounds3f;
+typedef Bounds3<double> Bounds3d;
+
+
+//-------------------------------------------------------------------------------------
+// ***** Size
+
+// Size class represents 2D size with Width, Height components.
+// Used to describe distentions of render targets, etc.
+
+template<class T>
+class Size
+{
+public:
+ T w, h;
+
+ Size() : w(0), h(0) { }
+ Size(T w_, T h_) : w(w_), h(h_) { }
+ explicit Size(T s) : w(s), h(s) { }
+ explicit Size(const Size<typename Math<T>::OtherFloatType> &src)
+ : w((T)src.w), h((T)src.h) { }
+
+ // C-interop support.
+ typedef typename CompatibleTypes<Size<T> >::Type CompatibleType;
+
+ Size(const CompatibleType& s) : w(s.w), h(s.h) { }
+
+ operator const CompatibleType& () const
+ {
+ OVR_MATH_STATIC_ASSERT(sizeof(Size<T>) == sizeof(CompatibleType), "sizeof(Size<T>) failure");
+ return reinterpret_cast<const CompatibleType&>(*this);
+ }
+
+ bool operator== (const Size& b) const { return w == b.w && h == b.h; }
+ bool operator!= (const Size& b) const { return w != b.w || h != b.h; }
+
+ Size operator+ (const Size& b) const { return Size(w + b.w, h + b.h); }
+ Size& operator+= (const Size& b) { w += b.w; h += b.h; return *this; }
+ Size operator- (const Size& b) const { return Size(w - b.w, h - b.h); }
+ Size& operator-= (const Size& b) { w -= b.w; h -= b.h; return *this; }
+ Size operator- () const { return Size(-w, -h); }
+ Size operator* (const Size& b) const { return Size(w * b.w, h * b.h); }
+ Size& operator*= (const Size& b) { w *= b.w; h *= b.h; return *this; }
+ Size operator/ (const Size& b) const { return Size(w / b.w, h / b.h); }
+ Size& operator/= (const Size& b) { w /= b.w; h /= b.h; return *this; }
+
+ // Scalar multiplication/division scales both components.
+ Size operator* (T s) const { return Size(w*s, h*s); }
+ Size& operator*= (T s) { w *= s; h *= s; return *this; }
+ Size operator/ (T s) const { return Size(w/s, h/s); }
+ Size& operator/= (T s) { w /= s; h /= s; return *this; }
+
+ static Size Min(const Size& a, const Size& b) { return Size((a.w < b.w) ? a.w : b.w,
+ (a.h < b.h) ? a.h : b.h); }
+ static Size Max(const Size& a, const Size& b) { return Size((a.w > b.w) ? a.w : b.w,
+ (a.h > b.h) ? a.h : b.h); }
+
+ T Area() const { return w * h; }
+
+ inline Vector2<T> ToVector() const { return Vector2<T>(w, h); }
+};
+
+
+typedef Size<int> Sizei;
+typedef Size<unsigned> Sizeu;
+typedef Size<float> Sizef;
+typedef Size<double> Sized;
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Rect
+
+// Rect describes a rectangular area for rendering, that includes position and size.
+template<class T>
+class Rect
+{
+public:
+ T x, y;
+ T w, h;
+
+ Rect() { }
+ Rect(T x1, T y1, T w1, T h1) : x(x1), y(y1), w(w1), h(h1) { }
+ Rect(const Vector2<T>& pos, const Size<T>& sz) : x(pos.x), y(pos.y), w(sz.w), h(sz.h) { }
+ Rect(const Size<T>& sz) : x(0), y(0), w(sz.w), h(sz.h) { }
+
+ // C-interop support.
+ typedef typename CompatibleTypes<Rect<T> >::Type CompatibleType;
+
+ Rect(const CompatibleType& s) : x(s.Pos.x), y(s.Pos.y), w(s.Size.w), h(s.Size.h) { }
+
+ operator const CompatibleType& () const
+ {
+ OVR_MATH_STATIC_ASSERT(sizeof(Rect<T>) == sizeof(CompatibleType), "sizeof(Rect<T>) failure");
+ return reinterpret_cast<const CompatibleType&>(*this);
+ }
+
+ Vector2<T> GetPos() const { return Vector2<T>(x, y); }
+ Size<T> GetSize() const { return Size<T>(w, h); }
+ void SetPos(const Vector2<T>& pos) { x = pos.x; y = pos.y; }
+ void SetSize(const Size<T>& sz) { w = sz.w; h = sz.h; }
+
+ bool operator == (const Rect& vp) const
+ { return (x == vp.x) && (y == vp.y) && (w == vp.w) && (h == vp.h); }
+ bool operator != (const Rect& vp) const
+ { return !operator == (vp); }
+};
+
+typedef Rect<int> Recti;
+
+
+//-------------------------------------------------------------------------------------//
+// ***** Quat
+//
+// Quatf represents a quaternion class used for rotations.
+//
+// Quaternion multiplications are done in right-to-left order, to match the
+// behavior of matrices.
+
+
+template<class T>
+class Quat
+{
+public:
+ typedef T ElementType;
+ static const size_t ElementCount = 4;
+
+ // x,y,z = axis*sin(angle), w = cos(angle)
+ T x, y, z, w;
+
+ Quat() : x(0), y(0), z(0), w(1) { }
+ Quat(T x_, T y_, T z_, T w_) : x(x_), y(y_), z(z_), w(w_) { }
+ explicit Quat(const Quat<typename Math<T>::OtherFloatType> &src)
+ : x((T)src.x), y((T)src.y), z((T)src.z), w((T)src.w)
+ {
+ // NOTE: Converting a normalized Quat<float> to Quat<double>
+ // will generally result in an un-normalized quaternion.
+ // But we don't normalize here in case the quaternion
+ // being converted is not a normalized rotation quaternion.
+ }
+
+ typedef typename CompatibleTypes<Quat<T> >::Type CompatibleType;
+
+ // C-interop support.
+ Quat(const CompatibleType& s) : x(s.x), y(s.y), z(s.z), w(s.w) { }
+
+ operator CompatibleType () const
+ {
+ CompatibleType result;
+ result.x = x;
+ result.y = y;
+ result.z = z;
+ result.w = w;
+ return result;
+ }
+
+ // Constructs quaternion for rotation around the axis by an angle.
+ Quat(const Vector3<T>& axis, T angle)
+ {
+ // Make sure we don't divide by zero.
+ if (axis.LengthSq() == T(0))
+ {
+ // Assert if the axis is zero, but the angle isn't
+ OVR_MATH_ASSERT(angle == T(0));
+ x = y = z = T(0); w = T(1);
+ return;
+ }
+
+ Vector3<T> unitAxis = axis.Normalized();
+ T sinHalfAngle = sin(angle * T(0.5));
+
+ w = cos(angle * T(0.5));
+ x = unitAxis.x * sinHalfAngle;
+ y = unitAxis.y * sinHalfAngle;
+ z = unitAxis.z * sinHalfAngle;
+ }
+
+ // Constructs quaternion for rotation around one of the coordinate axis by an angle.
+ Quat(Axis A, T angle, RotateDirection d = Rotate_CCW, HandedSystem s = Handed_R)
+ {
+ T sinHalfAngle = s * d *sin(angle * T(0.5));
+ T v[3];
+ v[0] = v[1] = v[2] = T(0);
+ v[A] = sinHalfAngle;
+
+ w = cos(angle * T(0.5));
+ x = v[0];
+ y = v[1];
+ z = v[2];
+ }
+
+ Quat operator-() { return Quat(-x, -y, -z, -w); } // unary minus
+
+ static Quat Identity() { return Quat(0, 0, 0, 1); }
+
+ // Compute axis and angle from quaternion
+ void GetAxisAngle(Vector3<T>* axis, T* angle) const
+ {
+ if ( x*x + y*y + z*z > Math<T>::Tolerance() * Math<T>::Tolerance() ) {
+ *axis = Vector3<T>(x, y, z).Normalized();
+ *angle = 2 * Acos(w);
+ if (*angle > ((T)MATH_DOUBLE_PI)) // Reduce the magnitude of the angle, if necessary
+ {
+ *angle = ((T)MATH_DOUBLE_TWOPI) - *angle;
+ *axis = *axis * (-1);
+ }
+ }
+ else
+ {
+ *axis = Vector3<T>(1, 0, 0);
+ *angle= T(0);
+ }
+ }
+
+ // Convert a quaternion to a rotation vector, also known as
+ // Rodrigues vector, AxisAngle vector, SORA vector, exponential map.
+ // A rotation vector describes a rotation about an axis:
+ // the axis of rotation is the vector normalized,
+ // the angle of rotation is the magnitude of the vector.
+ Vector3<T> ToRotationVector() const
+ {
+ OVR_MATH_ASSERT(IsNormalized() || LengthSq() == 0);
+ T s = T(0);
+ T sinHalfAngle = sqrt(x*x + y*y + z*z);
+ if (sinHalfAngle > T(0))
+ {
+ T cosHalfAngle = w;
+ T halfAngle = atan2(sinHalfAngle, cosHalfAngle);
+
+ // Ensure minimum rotation magnitude
+ if (cosHalfAngle < 0)
+ halfAngle -= T(MATH_DOUBLE_PI);
+
+ s = T(2) * halfAngle / sinHalfAngle;
+ }
+ return Vector3<T>(x*s, y*s, z*s);
+ }
+
+ // Faster version of the above, optimized for use with small rotations, where rotation angle ~= sin(angle)
+ inline OVR::Vector3<T> FastToRotationVector() const
+ {
+ OVR_MATH_ASSERT(IsNormalized());
+ T s;
+ T sinHalfSquared = x*x + y*y + z*z;
+ if (sinHalfSquared < T(.0037)) // =~ sin(7/2 degrees)^2
+ {
+ // Max rotation magnitude error is about .062% at 7 degrees rotation, or about .0043 degrees
+ s = T(2) * Sign(w);
+ }
+ else
+ {
+ T sinHalfAngle = sqrt(sinHalfSquared);
+ T cosHalfAngle = w;
+ T halfAngle = atan2(sinHalfAngle, cosHalfAngle);
+
+ // Ensure minimum rotation magnitude
+ if (cosHalfAngle < 0)
+ halfAngle -= T(MATH_DOUBLE_PI);
+
+ s = T(2) * halfAngle / sinHalfAngle;
+ }
+ return Vector3<T>(x*s, y*s, z*s);
+ }
+
+ // Given a rotation vector of form unitRotationAxis * angle,
+ // returns the equivalent quaternion (unitRotationAxis * sin(angle), cos(Angle)).
+ static Quat FromRotationVector(const Vector3<T>& v)
+ {
+ T angleSquared = v.LengthSq();
+ T s = T(0);
+ T c = T(1);
+ if (angleSquared > T(0))
+ {
+ T angle = sqrt(angleSquared);
+ s = sin(angle * T(0.5)) / angle; // normalize
+ c = cos(angle * T(0.5));
+ }
+ return Quat(s*v.x, s*v.y, s*v.z, c);
+ }
+
+ // Faster version of above, optimized for use with small rotation magnitudes, where rotation angle =~ sin(angle).
+ // If normalize is false, small-angle quaternions are returned un-normalized.
+ inline static Quat FastFromRotationVector(const OVR::Vector3<T>& v, bool normalize = true)
+ {
+ T s, c;
+ T angleSquared = v.LengthSq();
+ if (angleSquared < T(0.0076)) // =~ (5 degrees*pi/180)^2
+ {
+ s = T(0.5);
+ c = T(1.0);
+ // Max rotation magnitude error (after normalization) is about .064% at 5 degrees rotation, or .0032 degrees
+ if (normalize && angleSquared > 0)
+ {
+ // sin(angle/2)^2 ~= (angle/2)^2 and cos(angle/2)^2 ~= 1
+ T invLen = T(1) / sqrt(angleSquared * T(0.25) + T(1)); // normalize
+ s = s * invLen;
+ c = c * invLen;
+ }
+ }
+ else
+ {
+ T angle = sqrt(angleSquared);
+ s = sin(angle * T(0.5)) / angle;
+ c = cos(angle * T(0.5));
+ }
+ return Quat(s*v.x, s*v.y, s*v.z, c);
+ }
+
+ // Constructs the quaternion from a rotation matrix
+ explicit Quat(const Matrix4<T>& m)
+ {
+ T trace = m.M[0][0] + m.M[1][1] + m.M[2][2];
+
+ // In almost all cases, the first part is executed.
+ // However, if the trace is not positive, the other
+ // cases arise.
+ if (trace > T(0))
+ {
+ T s = sqrt(trace + T(1)) * T(2); // s=4*qw
+ w = T(0.25) * s;
+ x = (m.M[2][1] - m.M[1][2]) / s;
+ y = (m.M[0][2] - m.M[2][0]) / s;
+ z = (m.M[1][0] - m.M[0][1]) / s;
+ }
+ else if ((m.M[0][0] > m.M[1][1])&&(m.M[0][0] > m.M[2][2]))
+ {
+ T s = sqrt(T(1) + m.M[0][0] - m.M[1][1] - m.M[2][2]) * T(2);
+ w = (m.M[2][1] - m.M[1][2]) / s;
+ x = T(0.25) * s;
+ y = (m.M[0][1] + m.M[1][0]) / s;
+ z = (m.M[2][0] + m.M[0][2]) / s;
+ }
+ else if (m.M[1][1] > m.M[2][2])
+ {
+ T s = sqrt(T(1) + m.M[1][1] - m.M[0][0] - m.M[2][2]) * T(2); // S=4*qy
+ w = (m.M[0][2] - m.M[2][0]) / s;
+ x = (m.M[0][1] + m.M[1][0]) / s;
+ y = T(0.25) * s;
+ z = (m.M[1][2] + m.M[2][1]) / s;
+ }
+ else
+ {
+ T s = sqrt(T(1) + m.M[2][2] - m.M[0][0] - m.M[1][1]) * T(2); // S=4*qz
+ w = (m.M[1][0] - m.M[0][1]) / s;
+ x = (m.M[0][2] + m.M[2][0]) / s;
+ y = (m.M[1][2] + m.M[2][1]) / s;
+ z = T(0.25) * s;
+ }
+ OVR_MATH_ASSERT(IsNormalized()); // Ensure input matrix is orthogonal
+ }
+
+ // Constructs the quaternion from a rotation matrix
+ explicit Quat(const Matrix3<T>& m)
+ {
+ T trace = m.M[0][0] + m.M[1][1] + m.M[2][2];
+
+ // In almost all cases, the first part is executed.
+ // However, if the trace is not positive, the other
+ // cases arise.
+ if (trace > T(0))
+ {
+ T s = sqrt(trace + T(1)) * T(2); // s=4*qw
+ w = T(0.25) * s;
+ x = (m.M[2][1] - m.M[1][2]) / s;
+ y = (m.M[0][2] - m.M[2][0]) / s;
+ z = (m.M[1][0] - m.M[0][1]) / s;
+ }
+ else if ((m.M[0][0] > m.M[1][1])&&(m.M[0][0] > m.M[2][2]))
+ {
+ T s = sqrt(T(1) + m.M[0][0] - m.M[1][1] - m.M[2][2]) * T(2);
+ w = (m.M[2][1] - m.M[1][2]) / s;
+ x = T(0.25) * s;
+ y = (m.M[0][1] + m.M[1][0]) / s;
+ z = (m.M[2][0] + m.M[0][2]) / s;
+ }
+ else if (m.M[1][1] > m.M[2][2])
+ {
+ T s = sqrt(T(1) + m.M[1][1] - m.M[0][0] - m.M[2][2]) * T(2); // S=4*qy
+ w = (m.M[0][2] - m.M[2][0]) / s;
+ x = (m.M[0][1] + m.M[1][0]) / s;
+ y = T(0.25) * s;
+ z = (m.M[1][2] + m.M[2][1]) / s;
+ }
+ else
+ {
+ T s = sqrt(T(1) + m.M[2][2] - m.M[0][0] - m.M[1][1]) * T(2); // S=4*qz
+ w = (m.M[1][0] - m.M[0][1]) / s;
+ x = (m.M[0][2] + m.M[2][0]) / s;
+ y = (m.M[1][2] + m.M[2][1]) / s;
+ z = T(0.25) * s;
+ }
+ OVR_MATH_ASSERT(IsNormalized()); // Ensure input matrix is orthogonal
+ }
+
+ bool operator== (const Quat& b) const { return x == b.x && y == b.y && z == b.z && w == b.w; }
+ bool operator!= (const Quat& b) const { return x != b.x || y != b.y || z != b.z || w != b.w; }
+
+ Quat operator+ (const Quat& b) const { return Quat(x + b.x, y + b.y, z + b.z, w + b.w); }
+ Quat& operator+= (const Quat& b) { w += b.w; x += b.x; y += b.y; z += b.z; return *this; }
+ Quat operator- (const Quat& b) const { return Quat(x - b.x, y - b.y, z - b.z, w - b.w); }
+ Quat& operator-= (const Quat& b) { w -= b.w; x -= b.x; y -= b.y; z -= b.z; return *this; }
+
+ Quat operator* (T s) const { return Quat(x * s, y * s, z * s, w * s); }
+ Quat& operator*= (T s) { w *= s; x *= s; y *= s; z *= s; return *this; }
+ Quat operator/ (T s) const { T rcp = T(1)/s; return Quat(x * rcp, y * rcp, z * rcp, w *rcp); }
+ Quat& operator/= (T s) { T rcp = T(1)/s; w *= rcp; x *= rcp; y *= rcp; z *= rcp; return *this; }
+
+ // Compare two quats for equality within tolerance. Returns true if quats match withing tolerance.
+ bool IsEqual(const Quat& b, T tolerance = Math<T>::Tolerance()) const
+ {
+ return Abs(Dot(b)) >= T(1) - tolerance;
+ }
+
+ static T Abs(const T v) { return (v >= 0) ? v : -v; }
+
+ // Get Imaginary part vector
+ Vector3<T> Imag() const { return Vector3<T>(x,y,z); }
+
+ // Get quaternion length.
+ T Length() const { return sqrt(LengthSq()); }
+
+ // Get quaternion length squared.
+ T LengthSq() const { return (x * x + y * y + z * z + w * w); }
+
+ // Simple Euclidean distance in R^4 (not SLERP distance, but at least respects Haar measure)
+ T Distance(const Quat& q) const
+ {
+ T d1 = (*this - q).Length();
+ T d2 = (*this + q).Length(); // Antipodal point check
+ return (d1 < d2) ? d1 : d2;
+ }
+
+ T DistanceSq(const Quat& q) const
+ {
+ T d1 = (*this - q).LengthSq();
+ T d2 = (*this + q).LengthSq(); // Antipodal point check
+ return (d1 < d2) ? d1 : d2;
+ }
+
+ T Dot(const Quat& q) const
+ {
+ return x * q.x + y * q.y + z * q.z + w * q.w;
+ }
+
+ // Angle between two quaternions in radians
+ T Angle(const Quat& q) const
+ {
+ return T(2) * Acos(Abs(Dot(q)));
+ }
+
+ // Angle of quaternion
+ T Angle() const
+ {
+ return T(2) * Acos(Abs(w));
+ }
+
+ // Normalize
+ bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance(); }
+
+ void Normalize()
+ {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ *this *= s;
+ }
+
+ Quat Normalized() const
+ {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ return *this * s;
+ }
+
+ inline void EnsureSameHemisphere(const Quat& o)
+ {
+ if (Dot(o) < T(0))
+ {
+ x = -x;
+ y = -y;
+ z = -z;
+ w = -w;
+ }
+ }
+
+ // Returns conjugate of the quaternion. Produces inverse rotation if quaternion is normalized.
+ Quat Conj() const { return Quat(-x, -y, -z, w); }
+
+ // Quaternion multiplication. Combines quaternion rotations, performing the one on the
+ // right hand side first.
+ Quat operator* (const Quat& b) const { return Quat(w * b.x + x * b.w + y * b.z - z * b.y,
+ w * b.y - x * b.z + y * b.w + z * b.x,
+ w * b.z + x * b.y - y * b.x + z * b.w,
+ w * b.w - x * b.x - y * b.y - z * b.z); }
+ const Quat& operator*= (const Quat& b) { *this = *this * b; return *this; }
+
+ //
+ // this^p normalized; same as rotating by this p times.
+ Quat PowNormalized(T p) const
+ {
+ Vector3<T> v;
+ T a;
+ GetAxisAngle(&v, &a);
+ return Quat(v, a * p);
+ }
+
+ // Compute quaternion that rotates v into alignTo: alignTo = Quat::Align(alignTo, v).Rotate(v).
+ // NOTE: alignTo and v must be normalized.
+ static Quat Align(const Vector3<T>& alignTo, const Vector3<T>& v)
+ {
+ OVR_MATH_ASSERT(alignTo.IsNormalized() && v.IsNormalized());
+ Vector3<T> bisector = (v + alignTo);
+ bisector.Normalize();
+ T cosHalfAngle = v.Dot(bisector); // 0..1
+ if (cosHalfAngle > T(0))
+ {
+ Vector3<T> imag = v.Cross(bisector);
+ return Quat(imag.x, imag.y, imag.z, cosHalfAngle);
+ }
+ else
+ {
+ // cosHalfAngle == 0: a 180 degree rotation.
+ // sinHalfAngle == 1, rotation axis is any axis perpendicular
+ // to alignTo. Choose axis to include largest magnitude components
+ if (fabs(v.x) > fabs(v.y))
+ {
+ // x or z is max magnitude component
+ // = Cross(v, (0,1,0)).Normalized();
+ T invLen = sqrt(v.x*v.x + v.z*v.z);
+ if (invLen > T(0))
+ invLen = T(1) / invLen;
+ return Quat(-v.z*invLen, 0, v.x*invLen, 0);
+ }
+ else
+ {
+ // y or z is max magnitude component
+ // = Cross(v, (1,0,0)).Normalized();
+ T invLen = sqrt(v.y*v.y + v.z*v.z);
+ if (invLen > T(0))
+ invLen = T(1) / invLen;
+ return Quat(0, v.z*invLen, -v.y*invLen, 0);
+ }
+ }
+ }
+
+ // Decompose a quat into quat = swing * twist, where twist is a rotation about axis,
+ // and swing is a rotation perpendicular to axis.
+ Quat GetSwingTwist(const Vector3<T>& axis, Quat* twist) const
+ {
+ OVR_MATH_ASSERT(twist);
+ OVR_MATH_ASSERT(axis.IsNormalized());
+
+ // Create a normalized quaternion from projection of (x,y,z) onto axis
+ T d = axis.Dot(Vector3<T>(x, y, z));
+ *twist = Quat(axis.x*d, axis.y*d, axis.z*d, w);
+ T len = twist->Length();
+ if (len == 0)
+ twist->w = T(1); // identity
+ else
+ *twist /= len; // normalize
+
+ return *this * twist->Inverted();
+ }
+
+ // Normalized linear interpolation of quaternions
+ // NOTE: This function is a bad approximation of Slerp()
+ // when the angle between the *this and b is large.
+ // Use FastSlerp() or Slerp() instead.
+ Quat Lerp(const Quat& b, T s) const
+ {
+ return (*this * (T(1) - s) + b * (Dot(b) < 0 ? -s : s)).Normalized();
+ }
+
+ // Spherical linear interpolation between rotations
+ Quat Slerp(const Quat& b, T s) const
+ {
+ Vector3<T> delta = (b * this->Inverted()).ToRotationVector();
+ return (FromRotationVector(delta * s) * *this).Normalized(); // normalize so errors don't accumulate
+ }
+
+ // Spherical linear interpolation: much faster for small rotations, accurate for large rotations. See FastTo/FromRotationVector
+ Quat FastSlerp(const Quat& b, T s) const
+ {
+ Vector3<T> delta = (b * this->Inverted()).FastToRotationVector();
+ return (FastFromRotationVector(delta * s, false) * *this).Normalized();
+ }
+
+ // Rotate transforms vector in a manner that matches Matrix rotations (counter-clockwise,
+ // assuming negative direction of the axis). Standard formula: q(t) * V * q(t)^-1.
+ Vector3<T> Rotate(const Vector3<T>& v) const
+ {
+ OVR_MATH_ASSERT(isnan(w) || IsNormalized());
+
+ // rv = q * (v,0) * q'
+ // Same as rv = v + real * cross(imag,v)*2 + cross(imag, cross(imag,v)*2);
+
+ // uv = 2 * Imag().Cross(v);
+ T uvx = T(2) * (y*v.z - z*v.y);
+ T uvy = T(2) * (z*v.x - x*v.z);
+ T uvz = T(2) * (x*v.y - y*v.x);
+
+ // return v + Real()*uv + Imag().Cross(uv);
+ return Vector3<T>(v.x + w*uvx + y*uvz - z*uvy,
+ v.y + w*uvy + z*uvx - x*uvz,
+ v.z + w*uvz + x*uvy - y*uvx);
+ }
+
+ // Rotation by inverse of *this
+ Vector3<T> InverseRotate(const Vector3<T>& v) const
+ {
+ OVR_MATH_ASSERT(IsNormalized());
+
+ // rv = q' * (v,0) * q
+ // Same as rv = v + real * cross(-imag,v)*2 + cross(-imag, cross(-imag,v)*2);
+ // or rv = v - real * cross(imag,v)*2 + cross(imag, cross(imag,v)*2);
+
+ // uv = 2 * Imag().Cross(v);
+ T uvx = T(2) * (y*v.z - z*v.y);
+ T uvy = T(2) * (z*v.x - x*v.z);
+ T uvz = T(2) * (x*v.y - y*v.x);
+
+ // return v - Real()*uv + Imag().Cross(uv);
+ return Vector3<T>(v.x - w*uvx + y*uvz - z*uvy,
+ v.y - w*uvy + z*uvx - x*uvz,
+ v.z - w*uvz + x*uvy - y*uvx);
+ }
+
+ // Inversed quaternion rotates in the opposite direction.
+ Quat Inverted() const
+ {
+ return Quat(-x, -y, -z, w);
+ }
+
+ Quat Inverse() const
+ {
+ return Quat(-x, -y, -z, w);
+ }
+
+ // Sets this quaternion to the one rotates in the opposite direction.
+ void Invert()
+ {
+ *this = Quat(-x, -y, -z, w);
+ }
+
+ // Time integration of constant angular velocity over dt
+ Quat TimeIntegrate(Vector3<T> angularVelocity, T dt) const
+ {
+ // solution is: this * exp( omega*dt/2 ); FromRotationVector(v) gives exp(v*.5).
+ return (*this * FastFromRotationVector(angularVelocity * dt, false)).Normalized();
+ }
+
+ // Time integration of constant angular acceleration and velocity over dt
+ // These are the first two terms of the "Magnus expansion" of the solution
+ //
+ // o = o * exp( W=(W1 + W2 + W3+...) * 0.5 );
+ //
+ // omega1 = (omega + omegaDot*dt)
+ // W1 = (omega + omega1)*dt/2
+ // W2 = cross(omega, omega1)/12*dt^2 % (= -cross(omega_dot, omega)/12*dt^3)
+ // Terms 3 and beyond are vanishingly small:
+ // W3 = cross(omega_dot, cross(omega_dot, omega))/240*dt^5
+ //
+ Quat TimeIntegrate(Vector3<T> angularVelocity, Vector3<T> angularAcceleration, T dt) const
+ {
+ const Vector3<T>& omega = angularVelocity;
+ const Vector3<T>& omegaDot = angularAcceleration;
+
+ Vector3<T> omega1 = (omega + omegaDot * dt);
+ Vector3<T> W = ( (omega + omega1) + omega.Cross(omega1) * (dt/T(6)) ) * (dt/T(2));
+
+ // FromRotationVector(v) is exp(v*.5)
+ return (*this * FastFromRotationVector(W, false)).Normalized();
+ }
+
+ // Decompose rotation into three rotations:
+ // roll radians about Z axis, then pitch radians about X axis, then yaw radians about Y axis.
+ // Call with nullptr if a return value is not needed.
+ void GetYawPitchRoll(T* yaw, T* pitch, T* roll) const
+ {
+ return GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(yaw, pitch, roll);
+ }
+
+ // GetEulerAngles extracts Euler angles from the quaternion, in the specified order of
+ // axis rotations and the specified coordinate system. Right-handed coordinate system
+ // is the default, with CCW rotations while looking in the negative axis direction.
+ // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned.
+ // Rotation order is c, b, a:
+ // rotation c around axis A3
+ // is followed by rotation b around axis A2
+ // is followed by rotation a around axis A1
+ // rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ //
+ template <Axis A1, Axis A2, Axis A3, RotateDirection D, HandedSystem S>
+ void GetEulerAngles(T *a, T *b, T *c) const
+ {
+ OVR_MATH_ASSERT(IsNormalized());
+ OVR_MATH_STATIC_ASSERT((A1 != A2) && (A2 != A3) && (A1 != A3), "(A1 != A2) && (A2 != A3) && (A1 != A3)");
+
+ T Q[3] = { x, y, z }; //Quaternion components x,y,z
+
+ T ww = w*w;
+ T Q11 = Q[A1]*Q[A1];
+ T Q22 = Q[A2]*Q[A2];
+ T Q33 = Q[A3]*Q[A3];
+
+ T psign = T(-1);
+ // Determine whether even permutation
+ if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3))
+ psign = T(1);
+
+ T s2 = psign * T(2) * (psign*w*Q[A2] + Q[A1]*Q[A3]);
+
+ T singularityRadius = Math<T>::SingularityRadius();
+ if (s2 < T(-1) + singularityRadius)
+ { // South pole singularity
+ if (a) *a = T(0);
+ if (b) *b = -S*D*((T)MATH_DOUBLE_PIOVER2);
+ if (c) *c = S*D*atan2(T(2)*(psign*Q[A1] * Q[A2] + w*Q[A3]), ww + Q22 - Q11 - Q33 );
+ }
+ else if (s2 > T(1) - singularityRadius)
+ { // North pole singularity
+ if (a) *a = T(0);
+ if (b) *b = S*D*((T)MATH_DOUBLE_PIOVER2);
+ if (c) *c = S*D*atan2(T(2)*(psign*Q[A1] * Q[A2] + w*Q[A3]), ww + Q22 - Q11 - Q33);
+ }
+ else
+ {
+ if (a) *a = -S*D*atan2(T(-2)*(w*Q[A1] - psign*Q[A2] * Q[A3]), ww + Q33 - Q11 - Q22);
+ if (b) *b = S*D*asin(s2);
+ if (c) *c = S*D*atan2(T(2)*(w*Q[A3] - psign*Q[A1] * Q[A2]), ww + Q11 - Q22 - Q33);
+ }
+ }
+
+ template <Axis A1, Axis A2, Axis A3, RotateDirection D>
+ void GetEulerAngles(T *a, T *b, T *c) const
+ { GetEulerAngles<A1, A2, A3, D, Handed_R>(a, b, c); }
+
+ template <Axis A1, Axis A2, Axis A3>
+ void GetEulerAngles(T *a, T *b, T *c) const
+ { GetEulerAngles<A1, A2, A3, Rotate_CCW, Handed_R>(a, b, c); }
+
+ // GetEulerAnglesABA extracts Euler angles from the quaternion, in the specified order of
+ // axis rotations and the specified coordinate system. Right-handed coordinate system
+ // is the default, with CCW rotations while looking in the negative axis direction.
+ // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned.
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A1
+ // Rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, RotateDirection D, HandedSystem S>
+ void GetEulerAnglesABA(T *a, T *b, T *c) const
+ {
+ OVR_MATH_ASSERT(IsNormalized());
+ OVR_MATH_STATIC_ASSERT(A1 != A2, "A1 != A2");
+
+ T Q[3] = {x, y, z}; // Quaternion components
+
+ // Determine the missing axis that was not supplied
+ int m = 3 - A1 - A2;
+
+ T ww = w*w;
+ T Q11 = Q[A1]*Q[A1];
+ T Q22 = Q[A2]*Q[A2];
+ T Qmm = Q[m]*Q[m];
+
+ T psign = T(-1);
+ if ((A1 + 1) % 3 == A2) // Determine whether even permutation
+ {
+ psign = T(1);
+ }
+
+ T c2 = ww + Q11 - Q22 - Qmm;
+ T singularityRadius = Math<T>::SingularityRadius();
+ if (c2 < T(-1) + singularityRadius)
+ { // South pole singularity
+ if (a) *a = T(0);
+ if (b) *b = S*D*((T)MATH_DOUBLE_PI);
+ if (c) *c = S*D*atan2(T(2)*(w*Q[A1] - psign*Q[A2] * Q[m]),
+ ww + Q22 - Q11 - Qmm);
+ }
+ else if (c2 > T(1) - singularityRadius)
+ { // North pole singularity
+ if (a) *a = T(0);
+ if (b) *b = T(0);
+ if (c) *c = S*D*atan2(T(2)*(w*Q[A1] - psign*Q[A2] * Q[m]),
+ ww + Q22 - Q11 - Qmm);
+ }
+ else
+ {
+ if (a) *a = S*D*atan2(psign*w*Q[m] + Q[A1] * Q[A2],
+ w*Q[A2] -psign*Q[A1]*Q[m]);
+ if (b) *b = S*D*acos(c2);
+ if (c) *c = S*D*atan2(-psign*w*Q[m] + Q[A1] * Q[A2],
+ w*Q[A2] + psign*Q[A1]*Q[m]);
+ }
+ }
+};
+
+typedef Quat<float> Quatf;
+typedef Quat<double> Quatd;
+
+OVR_MATH_STATIC_ASSERT((sizeof(Quatf) == 4*sizeof(float)), "sizeof(Quatf) failure");
+OVR_MATH_STATIC_ASSERT((sizeof(Quatd) == 4*sizeof(double)), "sizeof(Quatd) failure");
+
+//-------------------------------------------------------------------------------------
+// ***** Pose
+//
+// Position and orientation combined.
+//
+// This structure needs to be the same size and layout on 32-bit and 64-bit arch.
+// Update OVR_PadCheck.cpp when updating this object.
+template<class T>
+class Pose
+{
+public:
+ typedef typename CompatibleTypes<Pose<T> >::Type CompatibleType;
+
+ Pose() { }
+ Pose(const Quat<T>& orientation, const Vector3<T>& pos)
+ : Rotation(orientation), Translation(pos) { }
+ Pose(const Pose& s)
+ : Rotation(s.Rotation), Translation(s.Translation) { }
+ Pose(const Matrix3<T>& R, const Vector3<T>& t)
+ : Rotation((Quat<T>)R), Translation(t) { }
+ Pose(const CompatibleType& s)
+ : Rotation(s.Orientation), Translation(s.Position) { }
+
+ explicit Pose(const Pose<typename Math<T>::OtherFloatType> &s)
+ : Rotation(s.Rotation), Translation(s.Translation)
+ {
+ // Ensure normalized rotation if converting from float to double
+ if (sizeof(T) > sizeof(typename Math<T>::OtherFloatType))
+ Rotation.Normalize();
+ }
+
+ static Pose Identity() { return Pose(Quat<T>(0, 0, 0, 1), Vector3<T>(0, 0, 0)); }
+
+ void SetIdentity() { Rotation = Quat<T>(0, 0, 0, 1); Translation = Vector3<T>(0, 0, 0); }
+
+ // used to make things obviously broken if someone tries to use the value
+ void SetInvalid() { Rotation = Quat<T>(NAN, NAN, NAN, NAN); Translation = Vector3<T>(NAN, NAN, NAN); }
+
+ bool IsEqual(const Pose&b, T tolerance = Math<T>::Tolerance()) const
+ {
+ return Translation.IsEqual(b.Translation, tolerance) && Rotation.IsEqual(b.Rotation, tolerance);
+ }
+
+ operator typename CompatibleTypes<Pose<T> >::Type () const
+ {
+ typename CompatibleTypes<Pose<T> >::Type result;
+ result.Orientation = Rotation;
+ result.Position = Translation;
+ return result;
+ }
+
+ Quat<T> Rotation;
+ Vector3<T> Translation;
+
+ OVR_MATH_STATIC_ASSERT((sizeof(T) == sizeof(double) || sizeof(T) == sizeof(float)), "(sizeof(T) == sizeof(double) || sizeof(T) == sizeof(float))");
+
+ void ToArray(T* arr) const
+ {
+ T temp[7] = { Rotation.x, Rotation.y, Rotation.z, Rotation.w, Translation.x, Translation.y, Translation.z };
+ for (int i = 0; i < 7; i++) arr[i] = temp[i];
+ }
+
+ static Pose<T> FromArray(const T* v)
+ {
+ Quat<T> rotation(v[0], v[1], v[2], v[3]);
+ Vector3<T> translation(v[4], v[5], v[6]);
+ // Ensure rotation is normalized, in case it was originally a float, stored in a .json file, etc.
+ return Pose<T>(rotation.Normalized(), translation);
+ }
+
+ Vector3<T> Rotate(const Vector3<T>& v) const
+ {
+ return Rotation.Rotate(v);
+ }
+
+ Vector3<T> InverseRotate(const Vector3<T>& v) const
+ {
+ return Rotation.InverseRotate(v);
+ }
+
+ Vector3<T> Translate(const Vector3<T>& v) const
+ {
+ return v + Translation;
+ }
+
+ Vector3<T> Transform(const Vector3<T>& v) const
+ {
+ return Rotate(v) + Translation;
+ }
+
+ Vector3<T> InverseTransform(const Vector3<T>& v) const
+ {
+ return InverseRotate(v - Translation);
+ }
+
+
+ Vector3<T> Apply(const Vector3<T>& v) const
+ {
+ return Transform(v);
+ }
+
+ Pose operator*(const Pose& other) const
+ {
+ return Pose(Rotation * other.Rotation, Apply(other.Translation));
+ }
+
+ Pose Inverted() const
+ {
+ Quat<T> inv = Rotation.Inverted();
+ return Pose(inv, inv.Rotate(-Translation));
+ }
+
+ // Interpolation between two poses: translation is interpolated with Lerp(),
+ // and rotations are interpolated with Slerp().
+ Pose Lerp(const Pose& b, T s)
+ {
+ return Pose(Rotation.Slerp(b.Rotation, s), Translation.Lerp(b.Translation, s));
+ }
+
+ // Similar to Lerp above, except faster in case of small rotation differences. See Quat<T>::FastSlerp.
+ Pose FastLerp(const Pose& b, T s)
+ {
+ return Pose(Rotation.FastSlerp(b.Rotation, s), Translation.Lerp(b.Translation, s));
+ }
+
+ Pose TimeIntegrate(const Vector3<T>& linearVelocity, const Vector3<T>& angularVelocity, T dt) const
+ {
+ return Pose(
+ (Rotation * Quat<T>::FastFromRotationVector(angularVelocity * dt, false)).Normalized(),
+ Translation + linearVelocity * dt);
+ }
+
+ Pose TimeIntegrate(const Vector3<T>& linearVelocity, const Vector3<T>& linearAcceleration,
+ const Vector3<T>& angularVelocity, const Vector3<T>& angularAcceleration,
+ T dt) const
+ {
+ return Pose(Rotation.TimeIntegrate(angularVelocity, angularAcceleration, dt),
+ Translation + linearVelocity*dt + linearAcceleration*dt*dt * T(0.5));
+ }
+};
+
+typedef Pose<float> Posef;
+typedef Pose<double> Posed;
+
+OVR_MATH_STATIC_ASSERT((sizeof(Posed) == sizeof(Quatd) + sizeof(Vector3d)), "sizeof(Posed) failure");
+OVR_MATH_STATIC_ASSERT((sizeof(Posef) == sizeof(Quatf) + sizeof(Vector3f)), "sizeof(Posef) failure");
+
+
+//-------------------------------------------------------------------------------------
+// ***** Matrix4
+//
+// Matrix4 is a 4x4 matrix used for 3d transformations and projections.
+// Translation stored in the last column.
+// The matrix is stored in row-major order in memory, meaning that values
+// of the first row are stored before the next one.
+//
+// The arrangement of the matrix is chosen to be in Right-Handed
+// coordinate system and counterclockwise rotations when looking down
+// the axis
+//
+// Transformation Order:
+// - Transformations are applied from right to left, so the expression
+// M1 * M2 * M3 * V means that the vector V is transformed by M3 first,
+// followed by M2 and M1.
+//
+// Coordinate system: Right Handed
+//
+// Rotations: Counterclockwise when looking down the axis. All angles are in radians.
+//
+// | sx 01 02 tx | // First column (sx, 10, 20): Axis X basis vector.
+// | 10 sy 12 ty | // Second column (01, sy, 21): Axis Y basis vector.
+// | 20 21 sz tz | // Third columnt (02, 12, sz): Axis Z basis vector.
+// | 30 31 32 33 |
+//
+// The basis vectors are first three columns.
+
+template<class T>
+class Matrix4
+{
+public:
+ typedef T ElementType;
+ static const size_t Dimension = 4;
+
+ T M[4][4];
+
+ enum NoInitType { NoInit };
+
+ // Construct with no memory initialization.
+ Matrix4(NoInitType) { }
+
+ // By default, we construct identity matrix.
+ Matrix4()
+ {
+ M[0][0] = M[1][1] = M[2][2] = M[3][3] = T(1);
+ M[0][1] = M[1][0] = M[2][3] = M[3][1] = T(0);
+ M[0][2] = M[1][2] = M[2][0] = M[3][2] = T(0);
+ M[0][3] = M[1][3] = M[2][1] = M[3][0] = T(0);
+ }
+
+ Matrix4(T m11, T m12, T m13, T m14,
+ T m21, T m22, T m23, T m24,
+ T m31, T m32, T m33, T m34,
+ T m41, T m42, T m43, T m44)
+ {
+ M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; M[0][3] = m14;
+ M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = m24;
+ M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = m34;
+ M[3][0] = m41; M[3][1] = m42; M[3][2] = m43; M[3][3] = m44;
+ }
+
+ Matrix4(T m11, T m12, T m13,
+ T m21, T m22, T m23,
+ T m31, T m32, T m33)
+ {
+ M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; M[0][3] = T(0);
+ M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = T(0);
+ M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = T(0);
+ M[3][0] = T(0); M[3][1] = T(0); M[3][2] = T(0); M[3][3] = T(1);
+ }
+
+ explicit Matrix4(const Matrix3<T>& m)
+ {
+ M[0][0] = m.M[0][0]; M[0][1] = m.M[0][1]; M[0][2] = m.M[0][2]; M[0][3] = T(0);
+ M[1][0] = m.M[1][0]; M[1][1] = m.M[1][1]; M[1][2] = m.M[1][2]; M[1][3] = T(0);
+ M[2][0] = m.M[2][0]; M[2][1] = m.M[2][1]; M[2][2] = m.M[2][2]; M[2][3] = T(0);
+ M[3][0] = T(0); M[3][1] = T(0); M[3][2] = T(0); M[3][3] = T(1);
+ }
+
+ explicit Matrix4(const Quat<T>& q)
+ {
+ OVR_MATH_ASSERT(q.IsNormalized());
+ T ww = q.w*q.w;
+ T xx = q.x*q.x;
+ T yy = q.y*q.y;
+ T zz = q.z*q.z;
+
+ M[0][0] = ww + xx - yy - zz; M[0][1] = 2 * (q.x*q.y - q.w*q.z); M[0][2] = 2 * (q.x*q.z + q.w*q.y); M[0][3] = T(0);
+ M[1][0] = 2 * (q.x*q.y + q.w*q.z); M[1][1] = ww - xx + yy - zz; M[1][2] = 2 * (q.y*q.z - q.w*q.x); M[1][3] = T(0);
+ M[2][0] = 2 * (q.x*q.z - q.w*q.y); M[2][1] = 2 * (q.y*q.z + q.w*q.x); M[2][2] = ww - xx - yy + zz; M[2][3] = T(0);
+ M[3][0] = T(0); M[3][1] = T(0); M[3][2] = T(0); M[3][3] = T(1);
+ }
+
+ explicit Matrix4(const Pose<T>& p)
+ {
+ Matrix4 result(p.Rotation);
+ result.SetTranslation(p.Translation);
+ *this = result;
+ }
+
+
+ // C-interop support
+ explicit Matrix4(const Matrix4<typename Math<T>::OtherFloatType> &src)
+ {
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ M[i][j] = (T)src.M[i][j];
+ }
+
+ // C-interop support.
+ Matrix4(const typename CompatibleTypes<Matrix4<T> >::Type& s)
+ {
+ OVR_MATH_STATIC_ASSERT(sizeof(s) == sizeof(Matrix4), "sizeof(s) == sizeof(Matrix4)");
+ memcpy(M, s.M, sizeof(M));
+ }
+
+ operator typename CompatibleTypes<Matrix4<T> >::Type () const
+ {
+ typename CompatibleTypes<Matrix4<T> >::Type result;
+ OVR_MATH_STATIC_ASSERT(sizeof(result) == sizeof(Matrix4), "sizeof(result) == sizeof(Matrix4)");
+ memcpy(result.M, M, sizeof(M));
+ return result;
+ }
+
+ void ToString(char* dest, size_t destsize) const
+ {
+ size_t pos = 0;
+ for (int r=0; r<4; r++)
+ {
+ for (int c=0; c<4; c++)
+ {
+ pos += OVRMath_sprintf(dest+pos, destsize-pos, "%g ", M[r][c]);
+ }
+ }
+ }
+
+ static Matrix4 FromString(const char* src)
+ {
+ Matrix4 result;
+ if (src)
+ {
+ for (int r = 0; r < 4; r++)
+ {
+ for (int c = 0; c < 4; c++)
+ {
+ result.M[r][c] = (T)atof(src);
+ while (*src && *src != ' ')
+ {
+ src++;
+ }
+ while (*src && *src == ' ')
+ {
+ src++;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ static Matrix4 Identity() { return Matrix4(); }
+
+ void SetIdentity()
+ {
+ M[0][0] = M[1][1] = M[2][2] = M[3][3] = T(1);
+ M[0][1] = M[1][0] = M[2][3] = M[3][1] = T(0);
+ M[0][2] = M[1][2] = M[2][0] = M[3][2] = T(0);
+ M[0][3] = M[1][3] = M[2][1] = M[3][0] = T(0);
+ }
+
+ void SetXBasis(const Vector3<T>& v)
+ {
+ M[0][0] = v.x;
+ M[1][0] = v.y;
+ M[2][0] = v.z;
+ }
+ Vector3<T> GetXBasis() const
+ {
+ return Vector3<T>(M[0][0], M[1][0], M[2][0]);
+ }
+
+ void SetYBasis(const Vector3<T> & v)
+ {
+ M[0][1] = v.x;
+ M[1][1] = v.y;
+ M[2][1] = v.z;
+ }
+ Vector3<T> GetYBasis() const
+ {
+ return Vector3<T>(M[0][1], M[1][1], M[2][1]);
+ }
+
+ void SetZBasis(const Vector3<T> & v)
+ {
+ M[0][2] = v.x;
+ M[1][2] = v.y;
+ M[2][2] = v.z;
+ }
+ Vector3<T> GetZBasis() const
+ {
+ return Vector3<T>(M[0][2], M[1][2], M[2][2]);
+ }
+
+ bool operator== (const Matrix4& b) const
+ {
+ bool isEqual = true;
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ isEqual &= (M[i][j] == b.M[i][j]);
+
+ return isEqual;
+ }
+
+ Matrix4 operator+ (const Matrix4& b) const
+ {
+ Matrix4 result(*this);
+ result += b;
+ return result;
+ }
+
+ Matrix4& operator+= (const Matrix4& b)
+ {
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ M[i][j] += b.M[i][j];
+ return *this;
+ }
+
+ Matrix4 operator- (const Matrix4& b) const
+ {
+ Matrix4 result(*this);
+ result -= b;
+ return result;
+ }
+
+ Matrix4& operator-= (const Matrix4& b)
+ {
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ M[i][j] -= b.M[i][j];
+ return *this;
+ }
+
+ // Multiplies two matrices into destination with minimum copying.
+ static Matrix4& Multiply(Matrix4* d, const Matrix4& a, const Matrix4& b)
+ {
+ OVR_MATH_ASSERT((d != &a) && (d != &b));
+ int i = 0;
+ do {
+ d->M[i][0] = a.M[i][0] * b.M[0][0] + a.M[i][1] * b.M[1][0] + a.M[i][2] * b.M[2][0] + a.M[i][3] * b.M[3][0];
+ d->M[i][1] = a.M[i][0] * b.M[0][1] + a.M[i][1] * b.M[1][1] + a.M[i][2] * b.M[2][1] + a.M[i][3] * b.M[3][1];
+ d->M[i][2] = a.M[i][0] * b.M[0][2] + a.M[i][1] * b.M[1][2] + a.M[i][2] * b.M[2][2] + a.M[i][3] * b.M[3][2];
+ d->M[i][3] = a.M[i][0] * b.M[0][3] + a.M[i][1] * b.M[1][3] + a.M[i][2] * b.M[2][3] + a.M[i][3] * b.M[3][3];
+ } while((++i) < 4);
+
+ return *d;
+ }
+
+ Matrix4 operator* (const Matrix4& b) const
+ {
+ Matrix4 result(Matrix4::NoInit);
+ Multiply(&result, *this, b);
+ return result;
+ }
+
+ Matrix4& operator*= (const Matrix4& b)
+ {
+ return Multiply(this, Matrix4(*this), b);
+ }
+
+ Matrix4 operator* (T s) const
+ {
+ Matrix4 result(*this);
+ result *= s;
+ return result;
+ }
+
+ Matrix4& operator*= (T s)
+ {
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ M[i][j] *= s;
+ return *this;
+ }
+
+
+ Matrix4 operator/ (T s) const
+ {
+ Matrix4 result(*this);
+ result /= s;
+ return result;
+ }
+
+ Matrix4& operator/= (T s)
+ {
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ M[i][j] /= s;
+ return *this;
+ }
+
+ Vector3<T> Transform(const Vector3<T>& v) const
+ {
+ const T rcpW = T(1) / (M[3][0] * v.x + M[3][1] * v.y + M[3][2] * v.z + M[3][3]);
+ return Vector3<T>((M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z + M[0][3]) * rcpW,
+ (M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z + M[1][3]) * rcpW,
+ (M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z + M[2][3]) * rcpW);
+ }
+
+ Vector4<T> Transform(const Vector4<T>& v) const
+ {
+ return Vector4<T>(M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z + M[0][3] * v.w,
+ M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z + M[1][3] * v.w,
+ M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z + M[2][3] * v.w,
+ M[3][0] * v.x + M[3][1] * v.y + M[3][2] * v.z + M[3][3] * v.w);
+ }
+
+ Matrix4 Transposed() const
+ {
+ return Matrix4(M[0][0], M[1][0], M[2][0], M[3][0],
+ M[0][1], M[1][1], M[2][1], M[3][1],
+ M[0][2], M[1][2], M[2][2], M[3][2],
+ M[0][3], M[1][3], M[2][3], M[3][3]);
+ }
+
+ void Transpose()
+ {
+ *this = Transposed();
+ }
+
+
+ T SubDet (const size_t* rows, const size_t* cols) const
+ {
+ return M[rows[0]][cols[0]] * (M[rows[1]][cols[1]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[1]])
+ - M[rows[0]][cols[1]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[0]])
+ + M[rows[0]][cols[2]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[1]] - M[rows[1]][cols[1]] * M[rows[2]][cols[0]]);
+ }
+
+ T Cofactor(size_t I, size_t J) const
+ {
+ const size_t indices[4][3] = {{1,2,3},{0,2,3},{0,1,3},{0,1,2}};
+ return ((I+J)&1) ? -SubDet(indices[I],indices[J]) : SubDet(indices[I],indices[J]);
+ }
+
+ T Determinant() const
+ {
+ return M[0][0] * Cofactor(0,0) + M[0][1] * Cofactor(0,1) + M[0][2] * Cofactor(0,2) + M[0][3] * Cofactor(0,3);
+ }
+
+ Matrix4 Adjugated() const
+ {
+ return Matrix4(Cofactor(0,0), Cofactor(1,0), Cofactor(2,0), Cofactor(3,0),
+ Cofactor(0,1), Cofactor(1,1), Cofactor(2,1), Cofactor(3,1),
+ Cofactor(0,2), Cofactor(1,2), Cofactor(2,2), Cofactor(3,2),
+ Cofactor(0,3), Cofactor(1,3), Cofactor(2,3), Cofactor(3,3));
+ }
+
+ Matrix4 Inverted() const
+ {
+ T det = Determinant();
+ OVR_MATH_ASSERT(det != 0);
+ return Adjugated() * (T(1)/det);
+ }
+
+ void Invert()
+ {
+ *this = Inverted();
+ }
+
+ // This is more efficient than general inverse, but ONLY works
+ // correctly if it is a homogeneous transform matrix (rot + trans)
+ Matrix4 InvertedHomogeneousTransform() const
+ {
+ // Make the inverse rotation matrix
+ Matrix4 rinv = this->Transposed();
+ rinv.M[3][0] = rinv.M[3][1] = rinv.M[3][2] = T(0);
+ // Make the inverse translation matrix
+ Vector3<T> tvinv(-M[0][3],-M[1][3],-M[2][3]);
+ Matrix4 tinv = Matrix4::Translation(tvinv);
+ return rinv * tinv; // "untranslate", then "unrotate"
+ }
+
+ // This is more efficient than general inverse, but ONLY works
+ // correctly if it is a homogeneous transform matrix (rot + trans)
+ void InvertHomogeneousTransform()
+ {
+ *this = InvertedHomogeneousTransform();
+ }
+
+ // Matrix to Euler Angles conversion
+ // a,b,c, are the YawPitchRoll angles to be returned
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A3
+ // rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, Axis A3, RotateDirection D, HandedSystem S>
+ void ToEulerAngles(T *a, T *b, T *c) const
+ {
+ OVR_MATH_STATIC_ASSERT((A1 != A2) && (A2 != A3) && (A1 != A3), "(A1 != A2) && (A2 != A3) && (A1 != A3)");
+
+ T psign = T(-1);
+ if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3)) // Determine whether even permutation
+ psign = T(1);
+
+ T pm = psign*M[A1][A3];
+ T singularityRadius = Math<T>::SingularityRadius();
+ if (pm < T(-1) + singularityRadius)
+ { // South pole singularity
+ *a = T(0);
+ *b = -S*D*((T)MATH_DOUBLE_PIOVER2);
+ *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] );
+ }
+ else if (pm > T(1) - singularityRadius)
+ { // North pole singularity
+ *a = T(0);
+ *b = S*D*((T)MATH_DOUBLE_PIOVER2);
+ *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] );
+ }
+ else
+ { // Normal case (nonsingular)
+ *a = S*D*atan2( -psign*M[A2][A3], M[A3][A3] );
+ *b = S*D*asin(pm);
+ *c = S*D*atan2( -psign*M[A1][A2], M[A1][A1] );
+ }
+ }
+
+ // Matrix to Euler Angles conversion
+ // a,b,c, are the YawPitchRoll angles to be returned
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A1
+ // rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, RotateDirection D, HandedSystem S>
+ void ToEulerAnglesABA(T *a, T *b, T *c) const
+ {
+ OVR_MATH_STATIC_ASSERT(A1 != A2, "A1 != A2");
+
+ // Determine the axis that was not supplied
+ int m = 3 - A1 - A2;
+
+ T psign = T(-1);
+ if ((A1 + 1) % 3 == A2) // Determine whether even permutation
+ psign = T(1);
+
+ T c2 = M[A1][A1];
+ T singularityRadius = Math<T>::SingularityRadius();
+ if (c2 < T(-1) + singularityRadius)
+ { // South pole singularity
+ *a = T(0);
+ *b = S*D*((T)MATH_DOUBLE_PI);
+ *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]);
+ }
+ else if (c2 > T(1) - singularityRadius)
+ { // North pole singularity
+ *a = T(0);
+ *b = T(0);
+ *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]);
+ }
+ else
+ { // Normal case (nonsingular)
+ *a = S*D*atan2( M[A2][A1],-psign*M[m][A1]);
+ *b = S*D*acos(c2);
+ *c = S*D*atan2( M[A1][A2],psign*M[A1][m]);
+ }
+ }
+
+ // Creates a matrix that converts the vertices from one coordinate system
+ // to another.
+ static Matrix4 AxisConversion(const WorldAxes& to, const WorldAxes& from)
+ {
+ // Holds axis values from the 'to' structure
+ int toArray[3] = { to.XAxis, to.YAxis, to.ZAxis };
+
+ // The inverse of the toArray
+ int inv[4];
+ inv[0] = inv[abs(to.XAxis)] = 0;
+ inv[abs(to.YAxis)] = 1;
+ inv[abs(to.ZAxis)] = 2;
+
+ Matrix4 m(0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0);
+
+ // Only three values in the matrix need to be changed to 1 or -1.
+ m.M[inv[abs(from.XAxis)]][0] = T(from.XAxis/toArray[inv[abs(from.XAxis)]]);
+ m.M[inv[abs(from.YAxis)]][1] = T(from.YAxis/toArray[inv[abs(from.YAxis)]]);
+ m.M[inv[abs(from.ZAxis)]][2] = T(from.ZAxis/toArray[inv[abs(from.ZAxis)]]);
+ return m;
+ }
+
+
+ // Creates a matrix for translation by vector
+ static Matrix4 Translation(const Vector3<T>& v)
+ {
+ Matrix4 t;
+ t.M[0][3] = v.x;
+ t.M[1][3] = v.y;
+ t.M[2][3] = v.z;
+ return t;
+ }
+
+ // Creates a matrix for translation by vector
+ static Matrix4 Translation(T x, T y, T z = T(0))
+ {
+ Matrix4 t;
+ t.M[0][3] = x;
+ t.M[1][3] = y;
+ t.M[2][3] = z;
+ return t;
+ }
+
+ // Sets the translation part
+ void SetTranslation(const Vector3<T>& v)
+ {
+ M[0][3] = v.x;
+ M[1][3] = v.y;
+ M[2][3] = v.z;
+ }
+
+ Vector3<T> GetTranslation() const
+ {
+ return Vector3<T>( M[0][3], M[1][3], M[2][3] );
+ }
+
+ // Creates a matrix for scaling by vector
+ static Matrix4 Scaling(const Vector3<T>& v)
+ {
+ Matrix4 t;
+ t.M[0][0] = v.x;
+ t.M[1][1] = v.y;
+ t.M[2][2] = v.z;
+ return t;
+ }
+
+ // Creates a matrix for scaling by vector
+ static Matrix4 Scaling(T x, T y, T z)
+ {
+ Matrix4 t;
+ t.M[0][0] = x;
+ t.M[1][1] = y;
+ t.M[2][2] = z;
+ return t;
+ }
+
+ // Creates a matrix for scaling by constant
+ static Matrix4 Scaling(T s)
+ {
+ Matrix4 t;
+ t.M[0][0] = s;
+ t.M[1][1] = s;
+ t.M[2][2] = s;
+ return t;
+ }
+
+ // Simple L1 distance in R^12
+ T Distance(const Matrix4& m2) const
+ {
+ T d = fabs(M[0][0] - m2.M[0][0]) + fabs(M[0][1] - m2.M[0][1]);
+ d += fabs(M[0][2] - m2.M[0][2]) + fabs(M[0][3] - m2.M[0][3]);
+ d += fabs(M[1][0] - m2.M[1][0]) + fabs(M[1][1] - m2.M[1][1]);
+ d += fabs(M[1][2] - m2.M[1][2]) + fabs(M[1][3] - m2.M[1][3]);
+ d += fabs(M[2][0] - m2.M[2][0]) + fabs(M[2][1] - m2.M[2][1]);
+ d += fabs(M[2][2] - m2.M[2][2]) + fabs(M[2][3] - m2.M[2][3]);
+ d += fabs(M[3][0] - m2.M[3][0]) + fabs(M[3][1] - m2.M[3][1]);
+ d += fabs(M[3][2] - m2.M[3][2]) + fabs(M[3][3] - m2.M[3][3]);
+ return d;
+ }
+
+ // Creates a rotation matrix rotating around the X axis by 'angle' radians.
+ // Just for quick testing. Not for final API. Need to remove case.
+ static Matrix4 RotationAxis(Axis A, T angle, RotateDirection d, HandedSystem s)
+ {
+ T sina = s * d *sin(angle);
+ T cosa = cos(angle);
+
+ switch(A)
+ {
+ case Axis_X:
+ return Matrix4(1, 0, 0,
+ 0, cosa, -sina,
+ 0, sina, cosa);
+ case Axis_Y:
+ return Matrix4(cosa, 0, sina,
+ 0, 1, 0,
+ -sina, 0, cosa);
+ case Axis_Z:
+ return Matrix4(cosa, -sina, 0,
+ sina, cosa, 0,
+ 0, 0, 1);
+ default:
+ return Matrix4();
+ }
+ }
+
+
+ // Creates a rotation matrix rotating around the X axis by 'angle' radians.
+ // Rotation direction is depends on the coordinate system:
+ // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
+ // while looking in the negative axis direction. This is the
+ // same as looking down from positive axis values towards origin.
+ // LHS: Positive angle values rotate clock-wise (CW), while looking in the
+ // negative axis direction.
+ static Matrix4 RotationX(T angle)
+ {
+ T sina = sin(angle);
+ T cosa = cos(angle);
+ return Matrix4(1, 0, 0,
+ 0, cosa, -sina,
+ 0, sina, cosa);
+ }
+
+ // Creates a rotation matrix rotating around the Y axis by 'angle' radians.
+ // Rotation direction is depends on the coordinate system:
+ // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
+ // while looking in the negative axis direction. This is the
+ // same as looking down from positive axis values towards origin.
+ // LHS: Positive angle values rotate clock-wise (CW), while looking in the
+ // negative axis direction.
+ static Matrix4 RotationY(T angle)
+ {
+ T sina = (T)sin(angle);
+ T cosa = (T)cos(angle);
+ return Matrix4(cosa, 0, sina,
+ 0, 1, 0,
+ -sina, 0, cosa);
+ }
+
+ // Creates a rotation matrix rotating around the Z axis by 'angle' radians.
+ // Rotation direction is depends on the coordinate system:
+ // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
+ // while looking in the negative axis direction. This is the
+ // same as looking down from positive axis values towards origin.
+ // LHS: Positive angle values rotate clock-wise (CW), while looking in the
+ // negative axis direction.
+ static Matrix4 RotationZ(T angle)
+ {
+ T sina = sin(angle);
+ T cosa = cos(angle);
+ return Matrix4(cosa, -sina, 0,
+ sina, cosa, 0,
+ 0, 0, 1);
+ }
+
+ // LookAtRH creates a View transformation matrix for right-handed coordinate system.
+ // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up'
+ // specifying the up vector. The resulting matrix should be used with PerspectiveRH
+ // projection.
+ static Matrix4 LookAtRH(const Vector3<T>& eye, const Vector3<T>& at, const Vector3<T>& up)
+ {
+ Vector3<T> z = (eye - at).Normalized(); // Forward
+ Vector3<T> x = up.Cross(z).Normalized(); // Right
+ Vector3<T> y = z.Cross(x);
+
+ Matrix4 m(x.x, x.y, x.z, -(x.Dot(eye)),
+ y.x, y.y, y.z, -(y.Dot(eye)),
+ z.x, z.y, z.z, -(z.Dot(eye)),
+ 0, 0, 0, 1 );
+ return m;
+ }
+
+ // LookAtLH creates a View transformation matrix for left-handed coordinate system.
+ // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up'
+ // specifying the up vector.
+ static Matrix4 LookAtLH(const Vector3<T>& eye, const Vector3<T>& at, const Vector3<T>& up)
+ {
+ Vector3<T> z = (at - eye).Normalized(); // Forward
+ Vector3<T> x = up.Cross(z).Normalized(); // Right
+ Vector3<T> y = z.Cross(x);
+
+ Matrix4 m(x.x, x.y, x.z, -(x.Dot(eye)),
+ y.x, y.y, y.z, -(y.Dot(eye)),
+ z.x, z.y, z.z, -(z.Dot(eye)),
+ 0, 0, 0, 1 );
+ return m;
+ }
+
+ // PerspectiveRH creates a right-handed perspective projection matrix that can be
+ // used with the Oculus sample renderer.
+ // yfov - Specifies vertical field of view in radians.
+ // aspect - Screen aspect ration, which is usually width/height for square pixels.
+ // Note that xfov = yfov * aspect.
+ // znear - Absolute value of near Z clipping clipping range.
+ // zfar - Absolute value of far Z clipping clipping range (larger then near).
+ // Even though RHS usually looks in the direction of negative Z, positive values
+ // are expected for znear and zfar.
+ static Matrix4 PerspectiveRH(T yfov, T aspect, T znear, T zfar)
+ {
+ Matrix4 m;
+ T tanHalfFov = tan(yfov * T(0.5));
+
+ m.M[0][0] = T(1) / (aspect * tanHalfFov);
+ m.M[1][1] = T(1) / tanHalfFov;
+ m.M[2][2] = zfar / (znear - zfar);
+ m.M[3][2] = T(-1);
+ m.M[2][3] = (zfar * znear) / (znear - zfar);
+ m.M[3][3] = T(0);
+
+ // Note: Post-projection matrix result assumes Left-Handed coordinate system,
+ // with Y up, X right and Z forward. This supports positive z-buffer values.
+ // This is the case even for RHS coordinate input.
+ return m;
+ }
+
+ // PerspectiveLH creates a left-handed perspective projection matrix that can be
+ // used with the Oculus sample renderer.
+ // yfov - Specifies vertical field of view in radians.
+ // aspect - Screen aspect ration, which is usually width/height for square pixels.
+ // Note that xfov = yfov * aspect.
+ // znear - Absolute value of near Z clipping clipping range.
+ // zfar - Absolute value of far Z clipping clipping range (larger then near).
+ static Matrix4 PerspectiveLH(T yfov, T aspect, T znear, T zfar)
+ {
+ Matrix4 m;
+ T tanHalfFov = tan(yfov * T(0.5));
+
+ m.M[0][0] = T(1) / (aspect * tanHalfFov);
+ m.M[1][1] = T(1) / tanHalfFov;
+ //m.M[2][2] = zfar / (znear - zfar);
+ m.M[2][2] = zfar / (zfar - znear);
+ m.M[3][2] = T(-1);
+ m.M[2][3] = (zfar * znear) / (znear - zfar);
+ m.M[3][3] = T(0);
+
+ // Note: Post-projection matrix result assumes Left-Handed coordinate system,
+ // with Y up, X right and Z forward. This supports positive z-buffer values.
+ // This is the case even for RHS coordinate input.
+ return m;
+ }
+
+ static Matrix4 Ortho2D(T w, T h)
+ {
+ Matrix4 m;
+ m.M[0][0] = T(2.0)/w;
+ m.M[1][1] = T(-2.0)/h;
+ m.M[0][3] = T(-1.0);
+ m.M[1][3] = T(1.0);
+ m.M[2][2] = T(0);
+ return m;
+ }
+};
+
+typedef Matrix4<float> Matrix4f;
+typedef Matrix4<double> Matrix4d;
+
+//-------------------------------------------------------------------------------------
+// ***** Matrix3
+//
+// Matrix3 is a 3x3 matrix used for representing a rotation matrix.
+// The matrix is stored in row-major order in memory, meaning that values
+// of the first row are stored before the next one.
+//
+// The arrangement of the matrix is chosen to be in Right-Handed
+// coordinate system and counterclockwise rotations when looking down
+// the axis
+//
+// Transformation Order:
+// - Transformations are applied from right to left, so the expression
+// M1 * M2 * M3 * V means that the vector V is transformed by M3 first,
+// followed by M2 and M1.
+//
+// Coordinate system: Right Handed
+//
+// Rotations: Counterclockwise when looking down the axis. All angles are in radians.
+
+template<class T>
+class Matrix3
+{
+public:
+ typedef T ElementType;
+ static const size_t Dimension = 3;
+
+ T M[3][3];
+
+ enum NoInitType { NoInit };
+
+ // Construct with no memory initialization.
+ Matrix3(NoInitType) { }
+
+ // By default, we construct identity matrix.
+ Matrix3()
+ {
+ M[0][0] = M[1][1] = M[2][2] = T(1);
+ M[0][1] = M[1][0] = M[2][0] = T(0);
+ M[0][2] = M[1][2] = M[2][1] = T(0);
+ }
+
+ Matrix3(T m11, T m12, T m13,
+ T m21, T m22, T m23,
+ T m31, T m32, T m33)
+ {
+ M[0][0] = m11; M[0][1] = m12; M[0][2] = m13;
+ M[1][0] = m21; M[1][1] = m22; M[1][2] = m23;
+ M[2][0] = m31; M[2][1] = m32; M[2][2] = m33;
+ }
+
+ // Construction from X, Y, Z basis vectors
+ Matrix3(const Vector3<T>& xBasis, const Vector3<T>& yBasis, const Vector3<T>& zBasis)
+ {
+ M[0][0] = xBasis.x; M[0][1] = yBasis.x; M[0][2] = zBasis.x;
+ M[1][0] = xBasis.y; M[1][1] = yBasis.y; M[1][2] = zBasis.y;
+ M[2][0] = xBasis.z; M[2][1] = yBasis.z; M[2][2] = zBasis.z;
+ }
+
+ explicit Matrix3(const Quat<T>& q)
+ {
+ OVR_MATH_ASSERT(q.IsNormalized());
+ const T tx = q.x+q.x, ty = q.y+q.y, tz = q.z+q.z;
+ const T twx = q.w*tx, twy = q.w*ty, twz = q.w*tz;
+ const T txx = q.x*tx, txy = q.x*ty, txz = q.x*tz;
+ const T tyy = q.y*ty, tyz = q.y*tz, tzz = q.z*tz;
+ M[0][0] = T(1) - (tyy + tzz); M[0][1] = txy - twz; M[0][2] = txz + twy;
+ M[1][0] = txy + twz; M[1][1] = T(1) - (txx + tzz); M[1][2] = tyz - twx;
+ M[2][0] = txz - twy; M[2][1] = tyz + twx; M[2][2] = T(1) - (txx + tyy);
+ }
+
+ inline explicit Matrix3(T s)
+ {
+ M[0][0] = M[1][1] = M[2][2] = s;
+ M[0][1] = M[0][2] = M[1][0] = M[1][2] = M[2][0] = M[2][1] = T(0);
+ }
+
+ Matrix3(T m11, T m22, T m33)
+ {
+ M[0][0] = m11; M[0][1] = T(0); M[0][2] = T(0);
+ M[1][0] = T(0); M[1][1] = m22; M[1][2] = T(0);
+ M[2][0] = T(0); M[2][1] = T(0); M[2][2] = m33;
+ }
+
+ explicit Matrix3(const Matrix3<typename Math<T>::OtherFloatType> &src)
+ {
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 3; j++)
+ M[i][j] = (T)src.M[i][j];
+ }
+
+ // C-interop support.
+ Matrix3(const typename CompatibleTypes<Matrix3<T> >::Type& s)
+ {
+ OVR_MATH_STATIC_ASSERT(sizeof(s) == sizeof(Matrix3), "sizeof(s) == sizeof(Matrix3)");
+ memcpy(M, s.M, sizeof(M));
+ }
+
+ operator const typename CompatibleTypes<Matrix3<T> >::Type () const
+ {
+ typename CompatibleTypes<Matrix3<T> >::Type result;
+ OVR_MATH_STATIC_ASSERT(sizeof(result) == sizeof(Matrix3), "sizeof(result) == sizeof(Matrix3)");
+ memcpy(result.M, M, sizeof(M));
+ return result;
+ }
+
+ T operator()(int i, int j) const { return M[i][j]; }
+ T& operator()(int i, int j) { return M[i][j]; }
+
+ void ToString(char* dest, size_t destsize) const
+ {
+ size_t pos = 0;
+ for (int r=0; r<3; r++)
+ {
+ for (int c=0; c<3; c++)
+ pos += OVRMath_sprintf(dest+pos, destsize-pos, "%g ", M[r][c]);
+ }
+ }
+
+ static Matrix3 FromString(const char* src)
+ {
+ Matrix3 result;
+ if (src)
+ {
+ for (int r=0; r<3; r++)
+ {
+ for (int c=0; c<3; c++)
+ {
+ result.M[r][c] = (T)atof(src);
+ while (*src && *src != ' ')
+ src++;
+ while (*src && *src == ' ')
+ src++;
+ }
+ }
+ }
+ return result;
+ }
+
+ static Matrix3 Identity() { return Matrix3(); }
+
+ void SetIdentity()
+ {
+ M[0][0] = M[1][1] = M[2][2] = T(1);
+ M[0][1] = M[1][0] = M[2][0] = T(0);
+ M[0][2] = M[1][2] = M[2][1] = T(0);
+ }
+
+ static Matrix3 Diagonal(T m00, T m11, T m22)
+ {
+ return Matrix3(m00, 0, 0,
+ 0, m11, 0,
+ 0, 0, m22);
+ }
+ static Matrix3 Diagonal(const Vector3<T>& v) { return Diagonal(v.x, v.y, v.z); }
+
+ T Trace() const { return M[0][0] + M[1][1] + M[2][2]; }
+
+ bool operator== (const Matrix3& b) const
+ {
+ bool isEqual = true;
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ isEqual &= (M[i][j] == b.M[i][j]);
+ }
+
+ return isEqual;
+ }
+
+ Matrix3 operator+ (const Matrix3& b) const
+ {
+ Matrix3<T> result(*this);
+ result += b;
+ return result;
+ }
+
+ Matrix3& operator+= (const Matrix3& b)
+ {
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 3; j++)
+ M[i][j] += b.M[i][j];
+ return *this;
+ }
+
+ void operator= (const Matrix3& b)
+ {
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 3; j++)
+ M[i][j] = b.M[i][j];
+ }
+
+ Matrix3 operator- (const Matrix3& b) const
+ {
+ Matrix3 result(*this);
+ result -= b;
+ return result;
+ }
+
+ Matrix3& operator-= (const Matrix3& b)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ M[i][j] -= b.M[i][j];
+ }
+
+ return *this;
+ }
+
+ // Multiplies two matrices into destination with minimum copying.
+ static Matrix3& Multiply(Matrix3* d, const Matrix3& a, const Matrix3& b)
+ {
+ OVR_MATH_ASSERT((d != &a) && (d != &b));
+ int i = 0;
+ do {
+ d->M[i][0] = a.M[i][0] * b.M[0][0] + a.M[i][1] * b.M[1][0] + a.M[i][2] * b.M[2][0];
+ d->M[i][1] = a.M[i][0] * b.M[0][1] + a.M[i][1] * b.M[1][1] + a.M[i][2] * b.M[2][1];
+ d->M[i][2] = a.M[i][0] * b.M[0][2] + a.M[i][1] * b.M[1][2] + a.M[i][2] * b.M[2][2];
+ } while((++i) < 3);
+
+ return *d;
+ }
+
+ Matrix3 operator* (const Matrix3& b) const
+ {
+ Matrix3 result(Matrix3::NoInit);
+ Multiply(&result, *this, b);
+ return result;
+ }
+
+ Matrix3& operator*= (const Matrix3& b)
+ {
+ return Multiply(this, Matrix3(*this), b);
+ }
+
+ Matrix3 operator* (T s) const
+ {
+ Matrix3 result(*this);
+ result *= s;
+ return result;
+ }
+
+ Matrix3& operator*= (T s)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ M[i][j] *= s;
+ }
+
+ return *this;
+ }
+
+ Vector3<T> operator* (const Vector3<T> &b) const
+ {
+ Vector3<T> result;
+ result.x = M[0][0]*b.x + M[0][1]*b.y + M[0][2]*b.z;
+ result.y = M[1][0]*b.x + M[1][1]*b.y + M[1][2]*b.z;
+ result.z = M[2][0]*b.x + M[2][1]*b.y + M[2][2]*b.z;
+
+ return result;
+ }
+
+ Matrix3 operator/ (T s) const
+ {
+ Matrix3 result(*this);
+ result /= s;
+ return result;
+ }
+
+ Matrix3& operator/= (T s)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ M[i][j] /= s;
+ }
+
+ return *this;
+ }
+
+ Vector2<T> Transform(const Vector2<T>& v) const
+ {
+ const T rcpZ = T(1) / (M[2][0] * v.x + M[2][1] * v.y + M[2][2]);
+ return Vector2<T>((M[0][0] * v.x + M[0][1] * v.y + M[0][2]) * rcpZ,
+ (M[1][0] * v.x + M[1][1] * v.y + M[1][2]) * rcpZ);
+ }
+
+ Vector3<T> Transform(const Vector3<T>& v) const
+ {
+ return Vector3<T>(M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z,
+ M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z,
+ M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z);
+ }
+
+ Matrix3 Transposed() const
+ {
+ return Matrix3(M[0][0], M[1][0], M[2][0],
+ M[0][1], M[1][1], M[2][1],
+ M[0][2], M[1][2], M[2][2]);
+ }
+
+ void Transpose()
+ {
+ *this = Transposed();
+ }
+
+
+ T SubDet (const size_t* rows, const size_t* cols) const
+ {
+ return M[rows[0]][cols[0]] * (M[rows[1]][cols[1]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[1]])
+ - M[rows[0]][cols[1]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[0]])
+ + M[rows[0]][cols[2]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[1]] - M[rows[1]][cols[1]] * M[rows[2]][cols[0]]);
+ }
+
+
+ // M += a*b.t()
+ inline void Rank1Add(const Vector3<T> &a, const Vector3<T> &b)
+ {
+ M[0][0] += a.x*b.x; M[0][1] += a.x*b.y; M[0][2] += a.x*b.z;
+ M[1][0] += a.y*b.x; M[1][1] += a.y*b.y; M[1][2] += a.y*b.z;
+ M[2][0] += a.z*b.x; M[2][1] += a.z*b.y; M[2][2] += a.z*b.z;
+ }
+
+ // M -= a*b.t()
+ inline void Rank1Sub(const Vector3<T> &a, const Vector3<T> &b)
+ {
+ M[0][0] -= a.x*b.x; M[0][1] -= a.x*b.y; M[0][2] -= a.x*b.z;
+ M[1][0] -= a.y*b.x; M[1][1] -= a.y*b.y; M[1][2] -= a.y*b.z;
+ M[2][0] -= a.z*b.x; M[2][1] -= a.z*b.y; M[2][2] -= a.z*b.z;
+ }
+
+ inline Vector3<T> Col(int c) const
+ {
+ return Vector3<T>(M[0][c], M[1][c], M[2][c]);
+ }
+
+ inline Vector3<T> Row(int r) const
+ {
+ return Vector3<T>(M[r][0], M[r][1], M[r][2]);
+ }
+
+ inline Vector3<T> GetColumn(int c) const
+ {
+ return Vector3<T>(M[0][c], M[1][c], M[2][c]);
+ }
+
+ inline Vector3<T> GetRow(int r) const
+ {
+ return Vector3<T>(M[r][0], M[r][1], M[r][2]);
+ }
+
+ inline void SetColumn(int c, const Vector3<T>& v)
+ {
+ M[0][c] = v.x;
+ M[1][c] = v.y;
+ M[2][c] = v.z;
+ }
+
+ inline void SetRow(int r, const Vector3<T>& v)
+ {
+ M[r][0] = v.x;
+ M[r][1] = v.y;
+ M[r][2] = v.z;
+ }
+
+ inline T Determinant() const
+ {
+ const Matrix3<T>& m = *this;
+ T d;
+
+ d = m.M[0][0] * (m.M[1][1]*m.M[2][2] - m.M[1][2] * m.M[2][1]);
+ d -= m.M[0][1] * (m.M[1][0]*m.M[2][2] - m.M[1][2] * m.M[2][0]);
+ d += m.M[0][2] * (m.M[1][0]*m.M[2][1] - m.M[1][1] * m.M[2][0]);
+
+ return d;
+ }
+
+ inline Matrix3<T> Inverse() const
+ {
+ Matrix3<T> a;
+ const Matrix3<T>& m = *this;
+ T d = Determinant();
+
+ OVR_MATH_ASSERT(d != 0);
+ T s = T(1)/d;
+
+ a.M[0][0] = s * (m.M[1][1] * m.M[2][2] - m.M[1][2] * m.M[2][1]);
+ a.M[1][0] = s * (m.M[1][2] * m.M[2][0] - m.M[1][0] * m.M[2][2]);
+ a.M[2][0] = s * (m.M[1][0] * m.M[2][1] - m.M[1][1] * m.M[2][0]);
+
+ a.M[0][1] = s * (m.M[0][2] * m.M[2][1] - m.M[0][1] * m.M[2][2]);
+ a.M[1][1] = s * (m.M[0][0] * m.M[2][2] - m.M[0][2] * m.M[2][0]);
+ a.M[2][1] = s * (m.M[0][1] * m.M[2][0] - m.M[0][0] * m.M[2][1]);
+
+ a.M[0][2] = s * (m.M[0][1] * m.M[1][2] - m.M[0][2] * m.M[1][1]);
+ a.M[1][2] = s * (m.M[0][2] * m.M[1][0] - m.M[0][0] * m.M[1][2]);
+ a.M[2][2] = s * (m.M[0][0] * m.M[1][1] - m.M[0][1] * m.M[1][0]);
+
+ return a;
+ }
+
+ // Outer Product of two column vectors: a * b.Transpose()
+ static Matrix3 OuterProduct(const Vector3<T>& a, const Vector3<T>& b)
+ {
+ return Matrix3(a.x*b.x, a.x*b.y, a.x*b.z,
+ a.y*b.x, a.y*b.y, a.y*b.z,
+ a.z*b.x, a.z*b.y, a.z*b.z);
+ }
+
+ // Vector cross product as a premultiply matrix:
+ // L.Cross(R) = LeftCrossAsMatrix(L) * R
+ static Matrix3 LeftCrossAsMatrix(const Vector3<T>& L)
+ {
+ return Matrix3(
+ T(0), -L.z, +L.y,
+ +L.z, T(0), -L.x,
+ -L.y, +L.x, T(0));
+ }
+
+ // Vector cross product as a premultiply matrix:
+ // L.Cross(R) = RightCrossAsMatrix(R) * L
+ static Matrix3 RightCrossAsMatrix(const Vector3<T>& R)
+ {
+ return Matrix3(
+ T(0), +R.z, -R.y,
+ -R.z, T(0), +R.x,
+ +R.y, -R.x, T(0));
+ }
+
+ // Angle in radians of a rotation matrix
+ // Uses identity trace(a) = 2*cos(theta) + 1
+ T Angle() const
+ {
+ return Acos((Trace() - T(1)) * T(0.5));
+ }
+
+ // Angle in radians between two rotation matrices
+ T Angle(const Matrix3& b) const
+ {
+ // Compute trace of (this->Transposed() * b)
+ // This works out to sum of products of elements.
+ T trace = T(0);
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ trace += M[i][j] * b.M[i][j];
+ }
+ }
+ return Acos((trace - T(1)) * T(0.5));
+ }
+};
+
+typedef Matrix3<float> Matrix3f;
+typedef Matrix3<double> Matrix3d;
+
+//-------------------------------------------------------------------------------------
+// ***** Matrix2
+
+template<class T>
+class Matrix2
+{
+public:
+ typedef T ElementType;
+ static const size_t Dimension = 2;
+
+ T M[2][2];
+
+ enum NoInitType { NoInit };
+
+ // Construct with no memory initialization.
+ Matrix2(NoInitType) { }
+
+ // By default, we construct identity matrix.
+ Matrix2()
+ {
+ M[0][0] = M[1][1] = T(1);
+ M[0][1] = M[1][0] = T(0);
+ }
+
+ Matrix2(T m11, T m12,
+ T m21, T m22)
+ {
+ M[0][0] = m11; M[0][1] = m12;
+ M[1][0] = m21; M[1][1] = m22;
+ }
+
+ // Construction from X, Y basis vectors
+ Matrix2(const Vector2<T>& xBasis, const Vector2<T>& yBasis)
+ {
+ M[0][0] = xBasis.x; M[0][1] = yBasis.x;
+ M[1][0] = xBasis.y; M[1][1] = yBasis.y;
+ }
+
+ explicit Matrix2(T s)
+ {
+ M[0][0] = M[1][1] = s;
+ M[0][1] = M[1][0] = T(0);
+ }
+
+ Matrix2(T m11, T m22)
+ {
+ M[0][0] = m11; M[0][1] = T(0);
+ M[1][0] = T(0); M[1][1] = m22;
+ }
+
+ explicit Matrix2(const Matrix2<typename Math<T>::OtherFloatType> &src)
+ {
+ M[0][0] = T(src.M[0][0]); M[0][1] = T(src.M[0][1]);
+ M[1][0] = T(src.M[1][0]); M[1][1] = T(src.M[1][1]);
+ }
+
+ // C-interop support
+ Matrix2(const typename CompatibleTypes<Matrix2<T> >::Type& s)
+ {
+ OVR_MATH_STATIC_ASSERT(sizeof(s) == sizeof(Matrix2), "sizeof(s) == sizeof(Matrix2)");
+ memcpy(M, s.M, sizeof(M));
+ }
+
+ operator const typename CompatibleTypes<Matrix2<T> >::Type() const
+ {
+ typename CompatibleTypes<Matrix2<T> >::Type result;
+ OVR_MATH_STATIC_ASSERT(sizeof(result) == sizeof(Matrix2), "sizeof(result) == sizeof(Matrix2)");
+ memcpy(result.M, M, sizeof(M));
+ return result;
+ }
+
+ T operator()(int i, int j) const { return M[i][j]; }
+ T& operator()(int i, int j) { return M[i][j]; }
+ const T* operator[](int i) const { return M[i]; }
+ T* operator[](int i) { return M[i]; }
+
+ static Matrix2 Identity() { return Matrix2(); }
+
+ void SetIdentity()
+ {
+ M[0][0] = M[1][1] = T(1);
+ M[0][1] = M[1][0] = T(0);
+ }
+
+ static Matrix2 Diagonal(T m00, T m11)
+ {
+ return Matrix2(m00, m11);
+ }
+ static Matrix2 Diagonal(const Vector2<T>& v) { return Matrix2(v.x, v.y); }
+
+ T Trace() const { return M[0][0] + M[1][1]; }
+
+ bool operator== (const Matrix2& b) const
+ {
+ return M[0][0] == b.M[0][0] && M[0][1] == b.M[0][1] &&
+ M[1][0] == b.M[1][0] && M[1][1] == b.M[1][1];
+ }
+
+ Matrix2 operator+ (const Matrix2& b) const
+ {
+ return Matrix2(M[0][0] + b.M[0][0], M[0][1] + b.M[0][1],
+ M[1][0] + b.M[1][0], M[1][1] + b.M[1][1]);
+ }
+
+ Matrix2& operator+= (const Matrix2& b)
+ {
+ M[0][0] += b.M[0][0]; M[0][1] += b.M[0][1];
+ M[1][0] += b.M[1][0]; M[1][1] += b.M[1][1];
+ return *this;
+ }
+
+ void operator= (const Matrix2& b)
+ {
+ M[0][0] = b.M[0][0]; M[0][1] = b.M[0][1];
+ M[1][0] = b.M[1][0]; M[1][1] = b.M[1][1];
+ }
+
+ Matrix2 operator- (const Matrix2& b) const
+ {
+ return Matrix2(M[0][0] - b.M[0][0], M[0][1] - b.M[0][1],
+ M[1][0] - b.M[1][0], M[1][1] - b.M[1][1]);
+ }
+
+ Matrix2& operator-= (const Matrix2& b)
+ {
+ M[0][0] -= b.M[0][0]; M[0][1] -= b.M[0][1];
+ M[1][0] -= b.M[1][0]; M[1][1] -= b.M[1][1];
+ return *this;
+ }
+
+ Matrix2 operator* (const Matrix2& b) const
+ {
+ return Matrix2(M[0][0] * b.M[0][0] + M[0][1] * b.M[1][0], M[0][0] * b.M[0][1] + M[0][1] * b.M[1][1],
+ M[1][0] * b.M[0][0] + M[1][1] * b.M[1][0], M[1][0] * b.M[0][1] + M[1][1] * b.M[1][1]);
+ }
+
+ Matrix2& operator*= (const Matrix2& b)
+ {
+ *this = *this * b;
+ return *this;
+ }
+
+ Matrix2 operator* (T s) const
+ {
+ return Matrix2(M[0][0] * s, M[0][1] * s,
+ M[1][0] * s, M[1][1] * s);
+ }
+
+ Matrix2& operator*= (T s)
+ {
+ M[0][0] *= s; M[0][1] *= s;
+ M[1][0] *= s; M[1][1] *= s;
+ return *this;
+ }
+
+ Matrix2 operator/ (T s) const
+ {
+ return *this * (T(1) / s);
+ }
+
+ Matrix2& operator/= (T s)
+ {
+ return *this *= (T(1) / s);
+ }
+
+ Vector2<T> operator* (const Vector2<T> &b) const
+ {
+ return Vector2<T>(M[0][0] * b.x + M[0][1] * b.y,
+ M[1][0] * b.x + M[1][1] * b.y);
+ }
+
+ Vector2<T> Transform(const Vector2<T>& v) const
+ {
+ return Vector2<T>(M[0][0] * v.x + M[0][1] * v.y,
+ M[1][0] * v.x + M[1][1] * v.y);
+ }
+
+ Matrix2 Transposed() const
+ {
+ return Matrix2(M[0][0], M[1][0],
+ M[0][1], M[1][1]);
+ }
+
+ void Transpose()
+ {
+ OVRMath_Swap(M[1][0], M[0][1]);
+ }
+
+ Vector2<T> GetColumn(int c) const
+ {
+ return Vector2<T>(M[0][c], M[1][c]);
+ }
+
+ Vector2<T> GetRow(int r) const
+ {
+ return Vector2<T>(M[r][0], M[r][1]);
+ }
+
+ void SetColumn(int c, const Vector2<T>& v)
+ {
+ M[0][c] = v.x;
+ M[1][c] = v.y;
+ }
+
+ void SetRow(int r, const Vector2<T>& v)
+ {
+ M[r][0] = v.x;
+ M[r][1] = v.y;
+ }
+
+ T Determinant() const
+ {
+ return M[0][0] * M[1][1] - M[0][1] * M[1][0];
+ }
+
+ Matrix2 Inverse() const
+ {
+ T rcpDet = T(1) / Determinant();
+ return Matrix2( M[1][1] * rcpDet, -M[0][1] * rcpDet,
+ -M[1][0] * rcpDet, M[0][0] * rcpDet);
+ }
+
+ // Outer Product of two column vectors: a * b.Transpose()
+ static Matrix2 OuterProduct(const Vector2<T>& a, const Vector2<T>& b)
+ {
+ return Matrix2(a.x*b.x, a.x*b.y,
+ a.y*b.x, a.y*b.y);
+ }
+
+ // Angle in radians between two rotation matrices
+ T Angle(const Matrix2& b) const
+ {
+ const Matrix2& a = *this;
+ return Acos(a(0, 0)*b(0, 0) + a(1, 0)*b(1, 0));
+ }
+};
+
+typedef Matrix2<float> Matrix2f;
+typedef Matrix2<double> Matrix2d;
+
+//-------------------------------------------------------------------------------------
+
+template<class T>
+class SymMat3
+{
+private:
+ typedef SymMat3<T> this_type;
+
+public:
+ typedef T Value_t;
+ // Upper symmetric
+ T v[6]; // _00 _01 _02 _11 _12 _22
+
+ inline SymMat3() {}
+
+ inline explicit SymMat3(T s)
+ {
+ v[0] = v[3] = v[5] = s;
+ v[1] = v[2] = v[4] = T(0);
+ }
+
+ inline explicit SymMat3(T a00, T a01, T a02, T a11, T a12, T a22)
+ {
+ v[0] = a00; v[1] = a01; v[2] = a02;
+ v[3] = a11; v[4] = a12;
+ v[5] = a22;
+ }
+
+ // Cast to symmetric Matrix3
+ operator Matrix3<T>() const
+ {
+ return Matrix3<T>(v[0], v[1], v[2],
+ v[1], v[3], v[4],
+ v[2], v[4], v[5]);
+ }
+
+ static inline int Index(unsigned int i, unsigned int j)
+ {
+ return (i <= j) ? (3*i - i*(i+1)/2 + j) : (3*j - j*(j+1)/2 + i);
+ }
+
+ inline T operator()(int i, int j) const { return v[Index(i,j)]; }
+
+ inline T &operator()(int i, int j) { return v[Index(i,j)]; }
+
+ inline this_type& operator+=(const this_type& b)
+ {
+ v[0]+=b.v[0];
+ v[1]+=b.v[1];
+ v[2]+=b.v[2];
+ v[3]+=b.v[3];
+ v[4]+=b.v[4];
+ v[5]+=b.v[5];
+ return *this;
+ }
+
+ inline this_type& operator-=(const this_type& b)
+ {
+ v[0]-=b.v[0];
+ v[1]-=b.v[1];
+ v[2]-=b.v[2];
+ v[3]-=b.v[3];
+ v[4]-=b.v[4];
+ v[5]-=b.v[5];
+
+ return *this;
+ }
+
+ inline this_type& operator*=(T s)
+ {
+ v[0]*=s;
+ v[1]*=s;
+ v[2]*=s;
+ v[3]*=s;
+ v[4]*=s;
+ v[5]*=s;
+
+ return *this;
+ }
+
+ inline SymMat3 operator*(T s) const
+ {
+ SymMat3 d;
+ d.v[0] = v[0]*s;
+ d.v[1] = v[1]*s;
+ d.v[2] = v[2]*s;
+ d.v[3] = v[3]*s;
+ d.v[4] = v[4]*s;
+ d.v[5] = v[5]*s;
+
+ return d;
+ }
+
+ // Multiplies two matrices into destination with minimum copying.
+ static SymMat3& Multiply(SymMat3* d, const SymMat3& a, const SymMat3& b)
+ {
+ // _00 _01 _02 _11 _12 _22
+
+ d->v[0] = a.v[0] * b.v[0];
+ d->v[1] = a.v[0] * b.v[1] + a.v[1] * b.v[3];
+ d->v[2] = a.v[0] * b.v[2] + a.v[1] * b.v[4];
+
+ d->v[3] = a.v[3] * b.v[3];
+ d->v[4] = a.v[3] * b.v[4] + a.v[4] * b.v[5];
+
+ d->v[5] = a.v[5] * b.v[5];
+
+ return *d;
+ }
+
+ inline T Determinant() const
+ {
+ const this_type& m = *this;
+ T d;
+
+ d = m(0,0) * (m(1,1)*m(2,2) - m(1,2) * m(2,1));
+ d -= m(0,1) * (m(1,0)*m(2,2) - m(1,2) * m(2,0));
+ d += m(0,2) * (m(1,0)*m(2,1) - m(1,1) * m(2,0));
+
+ return d;
+ }
+
+ inline this_type Inverse() const
+ {
+ this_type a;
+ const this_type& m = *this;
+ T d = Determinant();
+
+ OVR_MATH_ASSERT(d != 0);
+ T s = T(1)/d;
+
+ a(0,0) = s * (m(1,1) * m(2,2) - m(1,2) * m(2,1));
+
+ a(0,1) = s * (m(0,2) * m(2,1) - m(0,1) * m(2,2));
+ a(1,1) = s * (m(0,0) * m(2,2) - m(0,2) * m(2,0));
+
+ a(0,2) = s * (m(0,1) * m(1,2) - m(0,2) * m(1,1));
+ a(1,2) = s * (m(0,2) * m(1,0) - m(0,0) * m(1,2));
+ a(2,2) = s * (m(0,0) * m(1,1) - m(0,1) * m(1,0));
+
+ return a;
+ }
+
+ inline T Trace() const { return v[0] + v[3] + v[5]; }
+
+ // M = a*a.t()
+ inline void Rank1(const Vector3<T> &a)
+ {
+ v[0] = a.x*a.x; v[1] = a.x*a.y; v[2] = a.x*a.z;
+ v[3] = a.y*a.y; v[4] = a.y*a.z;
+ v[5] = a.z*a.z;
+ }
+
+ // M += a*a.t()
+ inline void Rank1Add(const Vector3<T> &a)
+ {
+ v[0] += a.x*a.x; v[1] += a.x*a.y; v[2] += a.x*a.z;
+ v[3] += a.y*a.y; v[4] += a.y*a.z;
+ v[5] += a.z*a.z;
+ }
+
+ // M -= a*a.t()
+ inline void Rank1Sub(const Vector3<T> &a)
+ {
+ v[0] -= a.x*a.x; v[1] -= a.x*a.y; v[2] -= a.x*a.z;
+ v[3] -= a.y*a.y; v[4] -= a.y*a.z;
+ v[5] -= a.z*a.z;
+ }
+};
+
+typedef SymMat3<float> SymMat3f;
+typedef SymMat3<double> SymMat3d;
+
+template<class T>
+inline Matrix3<T> operator*(const SymMat3<T>& a, const SymMat3<T>& b)
+{
+ #define AJB_ARBC(r,c) (a(r,0)*b(0,c)+a(r,1)*b(1,c)+a(r,2)*b(2,c))
+ return Matrix3<T>(
+ AJB_ARBC(0,0), AJB_ARBC(0,1), AJB_ARBC(0,2),
+ AJB_ARBC(1,0), AJB_ARBC(1,1), AJB_ARBC(1,2),
+ AJB_ARBC(2,0), AJB_ARBC(2,1), AJB_ARBC(2,2));
+ #undef AJB_ARBC
+}
+
+template<class T>
+inline Matrix3<T> operator*(const Matrix3<T>& a, const SymMat3<T>& b)
+{
+ #define AJB_ARBC(r,c) (a(r,0)*b(0,c)+a(r,1)*b(1,c)+a(r,2)*b(2,c))
+ return Matrix3<T>(
+ AJB_ARBC(0,0), AJB_ARBC(0,1), AJB_ARBC(0,2),
+ AJB_ARBC(1,0), AJB_ARBC(1,1), AJB_ARBC(1,2),
+ AJB_ARBC(2,0), AJB_ARBC(2,1), AJB_ARBC(2,2));
+ #undef AJB_ARBC
+}
+
+//-------------------------------------------------------------------------------------
+// ***** Angle
+
+// Cleanly representing the algebra of 2D rotations.
+// The operations maintain the angle between -Pi and Pi, the same range as atan2.
+
+template<class T>
+class Angle
+{
+public:
+ enum AngularUnits
+ {
+ Radians = 0,
+ Degrees = 1
+ };
+
+ Angle() : a(0) {}
+
+ // Fix the range to be between -Pi and Pi
+ Angle(T a_, AngularUnits u = Radians) : a((u == Radians) ? a_ : a_*((T)MATH_DOUBLE_DEGREETORADFACTOR)) { FixRange(); }
+
+ T Get(AngularUnits u = Radians) const { return (u == Radians) ? a : a*((T)MATH_DOUBLE_RADTODEGREEFACTOR); }
+ void Set(const T& x, AngularUnits u = Radians) { a = (u == Radians) ? x : x*((T)MATH_DOUBLE_DEGREETORADFACTOR); FixRange(); }
+ int Sign() const { if (a == 0) return 0; else return (a > 0) ? 1 : -1; }
+ T Abs() const { return (a >= 0) ? a : -a; }
+
+ bool operator== (const Angle& b) const { return a == b.a; }
+ bool operator!= (const Angle& b) const { return a != b.a; }
+// bool operator< (const Angle& b) const { return a < a.b; }
+// bool operator> (const Angle& b) const { return a > a.b; }
+// bool operator<= (const Angle& b) const { return a <= a.b; }
+// bool operator>= (const Angle& b) const { return a >= a.b; }
+// bool operator= (const T& x) { a = x; FixRange(); }
+
+ // These operations assume a is already between -Pi and Pi.
+ Angle& operator+= (const Angle& b) { a = a + b.a; FastFixRange(); return *this; }
+ Angle& operator+= (const T& x) { a = a + x; FixRange(); return *this; }
+ Angle operator+ (const Angle& b) const { Angle res = *this; res += b; return res; }
+ Angle operator+ (const T& x) const { Angle res = *this; res += x; return res; }
+ Angle& operator-= (const Angle& b) { a = a - b.a; FastFixRange(); return *this; }
+ Angle& operator-= (const T& x) { a = a - x; FixRange(); return *this; }
+ Angle operator- (const Angle& b) const { Angle res = *this; res -= b; return res; }
+ Angle operator- (const T& x) const { Angle res = *this; res -= x; return res; }
+
+ T Distance(const Angle& b) { T c = fabs(a - b.a); return (c <= ((T)MATH_DOUBLE_PI)) ? c : ((T)MATH_DOUBLE_TWOPI) - c; }
+
+private:
+
+ // The stored angle, which should be maintained between -Pi and Pi
+ T a;
+
+ // Fixes the angle range to [-Pi,Pi], but assumes no more than 2Pi away on either side
+ inline void FastFixRange()
+ {
+ if (a < -((T)MATH_DOUBLE_PI))
+ a += ((T)MATH_DOUBLE_TWOPI);
+ else if (a > ((T)MATH_DOUBLE_PI))
+ a -= ((T)MATH_DOUBLE_TWOPI);
+ }
+
+ // Fixes the angle range to [-Pi,Pi] for any given range, but slower then the fast method
+ inline void FixRange()
+ {
+ // do nothing if the value is already in the correct range, since fmod call is expensive
+ if (a >= -((T)MATH_DOUBLE_PI) && a <= ((T)MATH_DOUBLE_PI))
+ return;
+ a = fmod(a,((T)MATH_DOUBLE_TWOPI));
+ if (a < -((T)MATH_DOUBLE_PI))
+ a += ((T)MATH_DOUBLE_TWOPI);
+ else if (a > ((T)MATH_DOUBLE_PI))
+ a -= ((T)MATH_DOUBLE_TWOPI);
+ }
+};
+
+
+typedef Angle<float> Anglef;
+typedef Angle<double> Angled;
+
+
+//-------------------------------------------------------------------------------------
+// ***** Plane
+
+// Consists of a normal vector and distance from the origin where the plane is located.
+
+template<class T>
+class Plane
+{
+public:
+ Vector3<T> N;
+ T D;
+
+ Plane() : D(0) {}
+
+ // Normals must already be normalized
+ Plane(const Vector3<T>& n, T d) : N(n), D(d) {}
+ Plane(T x, T y, T z, T d) : N(x,y,z), D(d) {}
+
+ // construct from a point on the plane and the normal
+ Plane(const Vector3<T>& p, const Vector3<T>& n) : N(n), D(-(p * n)) {}
+
+ // Find the point to plane distance. The sign indicates what side of the plane the point is on (0 = point on plane).
+ T TestSide(const Vector3<T>& p) const
+ {
+ return (N.Dot(p)) + D;
+ }
+
+ Plane<T> Flipped() const
+ {
+ return Plane(-N, -D);
+ }
+
+ void Flip()
+ {
+ N = -N;
+ D = -D;
+ }
+
+ bool operator==(const Plane<T>& rhs) const
+ {
+ return (this->D == rhs.D && this->N == rhs.N);
+ }
+};
+
+typedef Plane<float> Planef;
+typedef Plane<double> Planed;
+
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** ScaleAndOffset2D
+
+struct ScaleAndOffset2D
+{
+ Vector2f Scale;
+ Vector2f Offset;
+
+ ScaleAndOffset2D(float sx = 0.0f, float sy = 0.0f, float ox = 0.0f, float oy = 0.0f)
+ : Scale(sx, sy), Offset(ox, oy)
+ { }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** FovPort
+
+// FovPort describes Field Of View (FOV) of a viewport.
+// This class has values for up, down, left and right, stored in
+// tangent of the angle units to simplify calculations.
+//
+// As an example, for a standard 90 degree vertical FOV, we would
+// have: { UpTan = tan(90 degrees / 2), DownTan = tan(90 degrees / 2) }.
+//
+// CreateFromRadians/Degrees helper functions can be used to
+// access FOV in different units.
+
+
+// ***** FovPort
+
+struct FovPort
+{
+ float UpTan;
+ float DownTan;
+ float LeftTan;
+ float RightTan;
+
+ FovPort ( float sideTan = 0.0f ) :
+ UpTan(sideTan), DownTan(sideTan), LeftTan(sideTan), RightTan(sideTan) { }
+ FovPort ( float u, float d, float l, float r ) :
+ UpTan(u), DownTan(d), LeftTan(l), RightTan(r) { }
+
+ // C-interop support: FovPort <-> ovrFovPort (implementation in OVR_CAPI.cpp).
+ FovPort(const ovrFovPort &src)
+ : UpTan(src.UpTan), DownTan(src.DownTan), LeftTan(src.LeftTan), RightTan(src.RightTan)
+ { }
+
+ operator ovrFovPort () const
+ {
+ ovrFovPort result;
+ result.LeftTan = LeftTan;
+ result.RightTan = RightTan;
+ result.UpTan = UpTan;
+ result.DownTan = DownTan;
+ return result;
+ }
+
+ static FovPort CreateFromRadians(float horizontalFov, float verticalFov)
+ {
+ FovPort result;
+ result.UpTan = tanf ( verticalFov * 0.5f );
+ result.DownTan = tanf ( verticalFov * 0.5f );
+ result.LeftTan = tanf ( horizontalFov * 0.5f );
+ result.RightTan = tanf ( horizontalFov * 0.5f );
+ return result;
+ }
+
+ static FovPort CreateFromDegrees(float horizontalFovDegrees,
+ float verticalFovDegrees)
+ {
+ return CreateFromRadians(DegreeToRad(horizontalFovDegrees),
+ DegreeToRad(verticalFovDegrees));
+ }
+
+ // Get Horizontal/Vertical components of Fov in radians.
+ float GetVerticalFovRadians() const { return atanf(UpTan) + atanf(DownTan); }
+ float GetHorizontalFovRadians() const { return atanf(LeftTan) + atanf(RightTan); }
+ // Get Horizontal/Vertical components of Fov in degrees.
+ float GetVerticalFovDegrees() const { return RadToDegree(GetVerticalFovRadians()); }
+ float GetHorizontalFovDegrees() const { return RadToDegree(GetHorizontalFovRadians()); }
+
+ // Compute maximum tangent value among all four sides.
+ float GetMaxSideTan() const
+ {
+ return OVRMath_Max(OVRMath_Max(UpTan, DownTan), OVRMath_Max(LeftTan, RightTan));
+ }
+
+ static ScaleAndOffset2D CreateNDCScaleAndOffsetFromFov ( FovPort tanHalfFov )
+ {
+ float projXScale = 2.0f / ( tanHalfFov.LeftTan + tanHalfFov.RightTan );
+ float projXOffset = ( tanHalfFov.LeftTan - tanHalfFov.RightTan ) * projXScale * 0.5f;
+ float projYScale = 2.0f / ( tanHalfFov.UpTan + tanHalfFov.DownTan );
+ float projYOffset = ( tanHalfFov.UpTan - tanHalfFov.DownTan ) * projYScale * 0.5f;
+
+ ScaleAndOffset2D result;
+ result.Scale = Vector2f(projXScale, projYScale);
+ result.Offset = Vector2f(projXOffset, projYOffset);
+ // Hey - why is that Y.Offset negated?
+ // It's because a projection matrix transforms from world coords with Y=up,
+ // whereas this is from NDC which is Y=down.
+
+ return result;
+ }
+
+ // Converts Fov Tan angle units to [-1,1] render target NDC space
+ Vector2f TanAngleToRendertargetNDC(Vector2f const &tanEyeAngle)
+ {
+ ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(*this);
+ return tanEyeAngle * eyeToSourceNDC.Scale + eyeToSourceNDC.Offset;
+ }
+
+ // Compute per-channel minimum and maximum of Fov.
+ static FovPort Min(const FovPort& a, const FovPort& b)
+ {
+ FovPort fov( OVRMath_Min( a.UpTan , b.UpTan ),
+ OVRMath_Min( a.DownTan , b.DownTan ),
+ OVRMath_Min( a.LeftTan , b.LeftTan ),
+ OVRMath_Min( a.RightTan, b.RightTan ) );
+ return fov;
+ }
+
+ static FovPort Max(const FovPort& a, const FovPort& b)
+ {
+ FovPort fov( OVRMath_Max( a.UpTan , b.UpTan ),
+ OVRMath_Max( a.DownTan , b.DownTan ),
+ OVRMath_Max( a.LeftTan , b.LeftTan ),
+ OVRMath_Max( a.RightTan, b.RightTan ) );
+ return fov;
+ }
+};
+
+
+} // Namespace OVR
+
+
+#if defined(_MSC_VER)
+ #pragma warning(pop)
+#endif
+
+
+#endif
diff --git a/src/external/OculusSDK/LibOVR/Include/Extras/OVR_StereoProjection.h b/src/external/OculusSDK/LibOVR/Include/Extras/OVR_StereoProjection.h
new file mode 100644
index 00000000..b4bc3bc7
--- /dev/null
+++ b/src/external/OculusSDK/LibOVR/Include/Extras/OVR_StereoProjection.h
@@ -0,0 +1,70 @@
+/************************************************************************************
+
+Filename : OVR_StereoProjection.h
+Content : Stereo projection functions
+Created : November 30, 2013
+Authors : Tom Fosyth
+
+Copyright : Copyright 2014-2016 Oculus VR, LLC All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.3 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.3
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*************************************************************************************/
+
+#ifndef OVR_StereoProjection_h
+#define OVR_StereoProjection_h
+
+
+#include "Extras/OVR_Math.h"
+
+
+namespace OVR {
+
+
+//-----------------------------------------------------------------------------------
+// ***** Stereo Enumerations
+
+// StereoEye specifies which eye we are rendering for; it is used to
+// retrieve StereoEyeParams.
+enum StereoEye
+{
+ StereoEye_Left,
+ StereoEye_Right,
+ StereoEye_Center
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Propjection functions
+
+Matrix4f CreateProjection ( bool rightHanded, bool isOpenGL, FovPort fov, StereoEye eye,
+ float zNear = 0.01f, float zFar = 10000.0f,
+ bool flipZ = false, bool farAtInfinity = false);
+
+Matrix4f CreateOrthoSubProjection ( bool rightHanded, StereoEye eyeType,
+ float tanHalfFovX, float tanHalfFovY,
+ float unitsX, float unitsY, float distanceFromCamera,
+ float interpupillaryDistance, Matrix4f const &projection,
+ float zNear = 0.0f, float zFar = 0.0f,
+ bool flipZ = false, bool farAtInfinity = false);
+
+ScaleAndOffset2D CreateNDCScaleAndOffsetFromFov ( FovPort fov );
+
+
+} //namespace OVR
+
+#endif // OVR_StereoProjection_h
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h
new file mode 100644
index 00000000..eaabcf59
--- /dev/null
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h
@@ -0,0 +1,2234 @@
+/********************************************************************************//**
+\file OVR_CAPI.h
+\brief C Interface to the Oculus PC SDK tracking and rendering library.
+\copyright Copyright 2014 Oculus VR, LLC All Rights reserved.
+************************************************************************************/
+
+#ifndef OVR_CAPI_h // We don't use version numbers within this name, as all versioned variations of this file are currently mutually exclusive.
+#define OVR_CAPI_h ///< Header include guard
+
+
+#include "OVR_CAPI_Keys.h"
+#include "OVR_Version.h"
+#include "OVR_ErrorCode.h"
+
+
+#include <stdint.h>
+
+#if defined(_MSC_VER)
+ #pragma warning(push)
+ #pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+ #pragma warning(disable: 4359) // The alignment specified for a type is less than the alignment of the type of one of its data members
+#endif
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_OS
+//
+#if !defined(OVR_OS_WIN32) && defined(_WIN32)
+ #define OVR_OS_WIN32
+#endif
+
+#if !defined(OVR_OS_MAC) && defined(__APPLE__)
+ #define OVR_OS_MAC
+#endif
+
+#if !defined(OVR_OS_LINUX) && defined(__linux__)
+ #define OVR_OS_LINUX
+#endif
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_CPP
+//
+#if !defined(OVR_CPP)
+ #if defined(__cplusplus)
+ #define OVR_CPP(x) x
+ #else
+ #define OVR_CPP(x) /* Not C++ */
+ #endif
+#endif
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_CDECL
+//
+/// LibOVR calling convention for 32-bit Windows builds.
+//
+#if !defined(OVR_CDECL)
+ #if defined(_WIN32)
+ #define OVR_CDECL __cdecl
+ #else
+ #define OVR_CDECL
+ #endif
+#endif
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_EXTERN_C
+//
+/// Defined as extern "C" when built from C++ code.
+//
+#if !defined(OVR_EXTERN_C)
+ #ifdef __cplusplus
+ #define OVR_EXTERN_C extern "C"
+ #else
+ #define OVR_EXTERN_C
+ #endif
+#endif
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_PUBLIC_FUNCTION / OVR_PRIVATE_FUNCTION
+//
+// OVR_PUBLIC_FUNCTION - Functions that externally visible from a shared library. Corresponds to Microsoft __dllexport.
+// OVR_PUBLIC_CLASS - C++ structs and classes that are externally visible from a shared library. Corresponds to Microsoft __dllexport.
+// OVR_PRIVATE_FUNCTION - Functions that are not visible outside of a shared library. They are private to the shared library.
+// OVR_PRIVATE_CLASS - C++ structs and classes that are not visible outside of a shared library. They are private to the shared library.
+//
+// OVR_DLL_BUILD - Used to indicate that the current compilation unit is of a shared library.
+// OVR_DLL_IMPORT - Used to indicate that the current compilation unit is a user of the corresponding shared library.
+// OVR_STATIC_BUILD - used to indicate that the current compilation unit is not a shared library but rather statically linked code.
+//
+#if !defined(OVR_PUBLIC_FUNCTION)
+ #if defined(OVR_DLL_BUILD)
+ #if defined(_WIN32)
+ #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C __declspec(dllexport) rval OVR_CDECL
+ #define OVR_PUBLIC_CLASS __declspec(dllexport)
+ #define OVR_PRIVATE_FUNCTION(rval) rval OVR_CDECL
+ #define OVR_PRIVATE_CLASS
+ #else
+ #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C __attribute__((visibility("default"))) rval OVR_CDECL /* Requires GCC 4.0+ */
+ #define OVR_PUBLIC_CLASS __attribute__((visibility("default"))) /* Requires GCC 4.0+ */
+ #define OVR_PRIVATE_FUNCTION(rval) __attribute__((visibility("hidden"))) rval OVR_CDECL
+ #define OVR_PRIVATE_CLASS __attribute__((visibility("hidden")))
+ #endif
+ #elif defined(OVR_DLL_IMPORT)
+ #if defined(_WIN32)
+ #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C __declspec(dllimport) rval OVR_CDECL
+ #define OVR_PUBLIC_CLASS __declspec(dllimport)
+ #else
+ #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C rval OVR_CDECL
+ #define OVR_PUBLIC_CLASS
+ #endif
+ #define OVR_PRIVATE_FUNCTION(rval) rval OVR_CDECL
+ #define OVR_PRIVATE_CLASS
+ #else // OVR_STATIC_BUILD
+ #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C rval OVR_CDECL
+ #define OVR_PUBLIC_CLASS
+ #define OVR_PRIVATE_FUNCTION(rval) rval OVR_CDECL
+ #define OVR_PRIVATE_CLASS
+ #endif
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_EXPORT
+//
+/// Provided for backward compatibility with older versions of this library.
+//
+#if !defined(OVR_EXPORT)
+ #ifdef OVR_OS_WIN32
+ #define OVR_EXPORT __declspec(dllexport)
+ #else
+ #define OVR_EXPORT
+ #endif
+#endif
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_ALIGNAS
+//
+#if !defined(OVR_ALIGNAS)
+ #if defined(__GNUC__) || defined(__clang__)
+ #define OVR_ALIGNAS(n) __attribute__((aligned(n)))
+ #elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
+ #define OVR_ALIGNAS(n) __declspec(align(n))
+ #elif defined(__CC_ARM)
+ #define OVR_ALIGNAS(n) __align(n)
+ #else
+ #error Need to define OVR_ALIGNAS
+ #endif
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_CC_HAS_FEATURE
+//
+// This is a portable way to use compile-time feature identification available
+// with some compilers in a clean way. Direct usage of __has_feature in preprocessing
+// statements of non-supporting compilers results in a preprocessing error.
+//
+// Example usage:
+// #if OVR_CC_HAS_FEATURE(is_pod)
+// if(__is_pod(T)) // If the type is plain data then we can safely memcpy it.
+// memcpy(&destObject, &srcObject, sizeof(object));
+// #endif
+//
+#if !defined(OVR_CC_HAS_FEATURE)
+ #if defined(__clang__) // http://clang.llvm.org/docs/LanguageExtensions.html#id2
+ #define OVR_CC_HAS_FEATURE(x) __has_feature(x)
+ #else
+ #define OVR_CC_HAS_FEATURE(x) 0
+ #endif
+#endif
+
+
+// ------------------------------------------------------------------------
+// ***** OVR_STATIC_ASSERT
+//
+// Portable support for C++11 static_assert().
+// Acts as if the following were declared:
+// void OVR_STATIC_ASSERT(bool const_expression, const char* msg);
+//
+// Example usage:
+// OVR_STATIC_ASSERT(sizeof(int32_t) == 4, "int32_t expected to be 4 bytes.");
+
+#if !defined(OVR_STATIC_ASSERT)
+ #if !(defined(__cplusplus) && (__cplusplus >= 201103L)) /* Other */ && \
+ !(defined(__GXX_EXPERIMENTAL_CXX0X__)) /* GCC */ && \
+ !(defined(__clang__) && defined(__cplusplus) && OVR_CC_HAS_FEATURE(cxx_static_assert)) /* clang */ && \
+ !(defined(_MSC_VER) && (_MSC_VER >= 1600) && defined(__cplusplus)) /* VS2010+ */
+
+ #if !defined(OVR_SA_UNUSED)
+ #if defined(OVR_CC_GNU) || defined(OVR_CC_CLANG)
+ #define OVR_SA_UNUSED __attribute__((unused))
+ #else
+ #define OVR_SA_UNUSED
+ #endif
+ #define OVR_SA_PASTE(a,b) a##b
+ #define OVR_SA_HELP(a,b) OVR_SA_PASTE(a,b)
+ #endif
+
+ #if defined(__COUNTER__)
+ #define OVR_STATIC_ASSERT(expression, msg) typedef char OVR_SA_HELP(compileTimeAssert, __COUNTER__) [((expression) != 0) ? 1 : -1] OVR_SA_UNUSED
+ #else
+ #define OVR_STATIC_ASSERT(expression, msg) typedef char OVR_SA_HELP(compileTimeAssert, __LINE__) [((expression) != 0) ? 1 : -1] OVR_SA_UNUSED
+ #endif
+
+ #else
+ #define OVR_STATIC_ASSERT(expression, msg) static_assert(expression, msg)
+ #endif
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** Padding
+//
+/// Defines explicitly unused space for a struct.
+/// When used correcly, usage of this macro should not change the size of the struct.
+/// Compile-time and runtime behavior with and without this defined should be identical.
+///
+#if !defined(OVR_UNUSED_STRUCT_PAD)
+ #define OVR_UNUSED_STRUCT_PAD(padName, size) char padName[size];
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** Word Size
+//
+/// Specifies the size of a pointer on the given platform.
+///
+#if !defined(OVR_PTR_SIZE)
+ #if defined(__WORDSIZE)
+ #define OVR_PTR_SIZE ((__WORDSIZE) / 8)
+ #elif defined(_WIN64) || defined(__LP64__) || defined(_LP64) || defined(_M_IA64) || defined(__ia64__) || defined(__arch64__) || defined(__64BIT__) || defined(__Ptr_Is_64)
+ #define OVR_PTR_SIZE 8
+ #elif defined(__CC_ARM) && (__sizeof_ptr == 8)
+ #define OVR_PTR_SIZE 8
+ #else
+ #define OVR_PTR_SIZE 4
+ #endif
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_ON32 / OVR_ON64
+//
+#if OVR_PTR_SIZE == 8
+ #define OVR_ON32(x)
+ #define OVR_ON64(x) x
+#else
+ #define OVR_ON32(x) x
+ #define OVR_ON64(x)
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** ovrBool
+
+typedef char ovrBool; ///< Boolean type
+#define ovrFalse 0 ///< ovrBool value of false.
+#define ovrTrue 1 ///< ovrBool value of true.
+
+
+//-----------------------------------------------------------------------------------
+// ***** Simple Math Structures
+
+/// A RGBA color with normalized float components.
+typedef struct OVR_ALIGNAS(4) ovrColorf_
+{
+ float r, g, b, a;
+} ovrColorf;
+
+/// A 2D vector with integer components.
+typedef struct OVR_ALIGNAS(4) ovrVector2i_
+{
+ int x, y;
+} ovrVector2i;
+
+/// A 2D size with integer components.
+typedef struct OVR_ALIGNAS(4) ovrSizei_
+{
+ int w, h;
+} ovrSizei;
+
+/// A 2D rectangle with a position and size.
+/// All components are integers.
+typedef struct OVR_ALIGNAS(4) ovrRecti_
+{
+ ovrVector2i Pos;
+ ovrSizei Size;
+} ovrRecti;
+
+/// A quaternion rotation.
+typedef struct OVR_ALIGNAS(4) ovrQuatf_
+{
+ float x, y, z, w;
+} ovrQuatf;
+
+/// A 2D vector with float components.
+typedef struct OVR_ALIGNAS(4) ovrVector2f_
+{
+ float x, y;
+} ovrVector2f;
+
+/// A 3D vector with float components.
+typedef struct OVR_ALIGNAS(4) ovrVector3f_
+{
+ float x, y, z;
+} ovrVector3f;
+
+/// A 4x4 matrix with float elements.
+typedef struct OVR_ALIGNAS(4) ovrMatrix4f_
+{
+ float M[4][4];
+} ovrMatrix4f;
+
+
+/// Position and orientation together.
+typedef struct OVR_ALIGNAS(4) ovrPosef_
+{
+ ovrQuatf Orientation;
+ ovrVector3f Position;
+} ovrPosef;
+
+/// A full pose (rigid body) configuration with first and second derivatives.
+///
+/// Body refers to any object for which ovrPoseStatef is providing data.
+/// It can be the HMD, Touch controller, sensor or something else. The context
+/// depends on the usage of the struct.
+typedef struct OVR_ALIGNAS(8) ovrPoseStatef_
+{
+ ovrPosef ThePose; ///< Position and orientation.
+ ovrVector3f AngularVelocity; ///< Angular velocity in radians per second.
+ ovrVector3f LinearVelocity; ///< Velocity in meters per second.
+ ovrVector3f AngularAcceleration; ///< Angular acceleration in radians per second per second.
+ ovrVector3f LinearAcceleration; ///< Acceleration in meters per second per second.
+ OVR_UNUSED_STRUCT_PAD(pad0, 4) ///< \internal struct pad.
+ double TimeInSeconds; ///< Absolute time that this pose refers to. \see ovr_GetTimeInSeconds
+} ovrPoseStatef;
+
+/// Describes the up, down, left, and right angles of the field of view.
+///
+/// Field Of View (FOV) tangent of the angle units.
+/// \note For a standard 90 degree vertical FOV, we would
+/// have: { UpTan = tan(90 degrees / 2), DownTan = tan(90 degrees / 2) }.
+typedef struct OVR_ALIGNAS(4) ovrFovPort_
+{
+ float UpTan; ///< The tangent of the angle between the viewing vector and the top edge of the field of view.
+ float DownTan; ///< The tangent of the angle between the viewing vector and the bottom edge of the field of view.
+ float LeftTan; ///< The tangent of the angle between the viewing vector and the left edge of the field of view.
+ float RightTan; ///< The tangent of the angle between the viewing vector and the right edge of the field of view.
+} ovrFovPort;
+
+
+//-----------------------------------------------------------------------------------
+// ***** HMD Types
+
+/// Enumerates all HMD types that we support.
+///
+/// The currently released developer kits are ovrHmd_DK1 and ovrHmd_DK2. The other enumerations are for internal use only.
+typedef enum ovrHmdType_
+{
+ ovrHmd_None = 0,
+ ovrHmd_DK1 = 3,
+ ovrHmd_DKHD = 4,
+ ovrHmd_DK2 = 6,
+ ovrHmd_CB = 8,
+ ovrHmd_Other = 9,
+ ovrHmd_E3_2015 = 10,
+ ovrHmd_ES06 = 11,
+ ovrHmd_ES09 = 12,
+ ovrHmd_ES11 = 13,
+ ovrHmd_CV1 = 14,
+
+ ovrHmd_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrHmdType;
+
+
+/// HMD capability bits reported by device.
+///
+typedef enum ovrHmdCaps_
+{
+ // Read-only flags
+ ovrHmdCap_DebugDevice = 0x0010, ///< <B>(read only)</B> Specifies that the HMD is a virtual debug device.
+
+
+ ovrHmdCap_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrHmdCaps;
+
+
+/// Tracking capability bits reported by the device.
+/// Used with ovr_GetTrackingCaps.
+typedef enum ovrTrackingCaps_
+{
+ ovrTrackingCap_Orientation = 0x0010, ///< Supports orientation tracking (IMU).
+ ovrTrackingCap_MagYawCorrection = 0x0020, ///< Supports yaw drift correction via a magnetometer or other means.
+ ovrTrackingCap_Position = 0x0040, ///< Supports positional tracking.
+ ovrTrackingCap_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrTrackingCaps;
+
+
+/// Specifies which eye is being used for rendering.
+/// This type explicitly does not include a third "NoStereo" monoscopic option, as such is
+/// not required for an HMD-centered API.
+typedef enum ovrEyeType_
+{
+ ovrEye_Left = 0, ///< The left eye, from the viewer's perspective.
+ ovrEye_Right = 1, ///< The right eye, from the viewer's perspective.
+ ovrEye_Count = 2, ///< \internal Count of enumerated elements.
+ ovrEye_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrEyeType;
+
+/// Specifies the coordinate system ovrTrackingState returns tracking poses in.
+/// Used with ovr_SetTrackingOriginType()
+typedef enum ovrTrackingOrigin_
+{
+ /// \brief Tracking system origin reported at eye (HMD) height
+ /// \details Prefer using this origin when your application requires
+ /// matching user's current physical head pose to a virtual head pose
+ /// without any regards to a the height of the floor. Cockpit-based,
+ /// or 3rd-person experiences are ideal candidates.
+ /// When used, all poses in ovrTrackingState are reported as an offset
+ /// transform from the profile calibrated or recentered HMD pose.
+ /// It is recommended that apps using this origin type call ovr_RecenterTrackingOrigin
+ /// prior to starting the VR experience, but notify the user before doing so
+ /// to make sure the user is in a comfortable pose, facing a comfortable
+ /// direction.
+ ovrTrackingOrigin_EyeLevel = 0,
+ /// \brief Tracking system origin reported at floor height
+ /// \details Prefer using this origin when your application requires the
+ /// physical floor height to match the virtual floor height, such as
+ /// standing experiences.
+ /// When used, all poses in ovrTrackingState are reported as an offset
+ /// transform from the profile calibrated floor pose. Calling ovr_RecenterTrackingOrigin
+ /// will recenter the X & Z axes as well as yaw, but the Y-axis (i.e. height) will continue
+ /// to be reported using the floor height as the origin for all poses.
+ ovrTrackingOrigin_FloorLevel = 1,
+ ovrTrackingOrigin_Count = 2, ///< \internal Count of enumerated elements.
+ ovrTrackingOrigin_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrTrackingOrigin;
+
+/// Identifies a graphics device in a platform-specific way.
+/// For Windows this is a LUID type.
+typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrGraphicsLuid_
+{
+ // Public definition reserves space for graphics API-specific implementation
+ char Reserved[8];
+} ovrGraphicsLuid;
+
+
+/// This is a complete descriptor of the HMD.
+typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrHmdDesc_
+{
+ ovrHmdType Type; ///< The type of HMD.
+ OVR_ON64(OVR_UNUSED_STRUCT_PAD(pad0, 4)) ///< \internal struct paddding.
+ char ProductName[64]; ///< UTF8-encoded product identification string (e.g. "Oculus Rift DK1").
+ char Manufacturer[64]; ///< UTF8-encoded HMD manufacturer identification string.
+ short VendorId; ///< HID (USB) vendor identifier of the device.
+ short ProductId; ///< HID (USB) product identifier of the device.
+ char SerialNumber[24]; ///< HMD serial number.
+ short FirmwareMajor; ///< HMD firmware major version.
+ short FirmwareMinor; ///< HMD firmware minor version.
+ unsigned int AvailableHmdCaps; ///< Capability bits described by ovrHmdCaps which the HMD currently supports.
+ unsigned int DefaultHmdCaps; ///< Capability bits described by ovrHmdCaps which are default for the current Hmd.
+ unsigned int AvailableTrackingCaps; ///< Capability bits described by ovrTrackingCaps which the system currently supports.
+ unsigned int DefaultTrackingCaps; ///< Capability bits described by ovrTrackingCaps which are default for the current system.
+ ovrFovPort DefaultEyeFov[ovrEye_Count]; ///< Defines the recommended FOVs for the HMD.
+ ovrFovPort MaxEyeFov[ovrEye_Count]; ///< Defines the maximum FOVs for the HMD.
+ ovrSizei Resolution; ///< Resolution of the full HMD screen (both eyes) in pixels.
+ float DisplayRefreshRate; ///< Nominal refresh rate of the display in cycles per second at the time of HMD creation.
+ OVR_ON64(OVR_UNUSED_STRUCT_PAD(pad1, 4)) ///< \internal struct paddding.
+} ovrHmdDesc;
+
+
+/// Used as an opaque pointer to an OVR session.
+typedef struct ovrHmdStruct* ovrSession;
+
+
+
+/// Bit flags describing the current status of sensor tracking.
+/// The values must be the same as in enum StatusBits
+///
+/// \see ovrTrackingState
+///
+typedef enum ovrStatusBits_
+{
+ ovrStatus_OrientationTracked = 0x0001, ///< Orientation is currently tracked (connected and in use).
+ ovrStatus_PositionTracked = 0x0002, ///< Position is currently tracked (false if out of range).
+ ovrStatus_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrStatusBits;
+
+
+/// Specifies the description of a single sensor.
+///
+/// \see ovr_GetTrackerDesc
+///
+typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrTrackerDesc_
+{
+ float FrustumHFovInRadians; ///< Sensor frustum horizontal field-of-view (if present).
+ float FrustumVFovInRadians; ///< Sensor frustum vertical field-of-view (if present).
+ float FrustumNearZInMeters; ///< Sensor frustum near Z (if present).
+ float FrustumFarZInMeters; ///< Sensor frustum far Z (if present).
+} ovrTrackerDesc;
+
+
+/// Specifies sensor flags.
+///
+/// /see ovrTrackerPose
+///
+typedef enum ovrTrackerFlags_
+{
+ ovrTracker_Connected = 0x0020, ///< The sensor is present, else the sensor is absent or offline.
+ ovrTracker_PoseTracked = 0x0004 ///< The sensor has a valid pose, else the pose is unavailable. This will only be set if ovrTracker_Connected is set.
+} ovrTrackerFlags;
+
+
+/// Specifies the pose for a single sensor.
+///
+typedef struct OVR_ALIGNAS(8) _ovrTrackerPose
+{
+ unsigned int TrackerFlags; ///< ovrTrackerFlags.
+ ovrPosef Pose; ///< The sensor's pose. This pose includes sensor tilt (roll and pitch). For a leveled coordinate system use LeveledPose.
+ ovrPosef LeveledPose; ///< The sensor's leveled pose, aligned with gravity. This value includes position and yaw of the sensor, but not roll and pitch. It can be used as a reference point to render real-world objects in the correct location.
+ OVR_UNUSED_STRUCT_PAD(pad0, 4) ///< \internal struct pad.
+} ovrTrackerPose;
+
+
+/// Tracking state at a given absolute time (describes predicted HMD pose, etc.).
+/// Returned by ovr_GetTrackingState.
+///
+/// \see ovr_GetTrackingState
+///
+typedef struct OVR_ALIGNAS(8) ovrTrackingState_
+{
+ /// Predicted head pose (and derivatives) at the requested absolute time.
+ ovrPoseStatef HeadPose;
+
+ /// HeadPose tracking status described by ovrStatusBits.
+ unsigned int StatusFlags;
+
+ /// The most recent calculated pose for each hand when hand controller tracking is present.
+ /// HandPoses[ovrHand_Left] refers to the left hand and HandPoses[ovrHand_Right] to the right hand.
+ /// These values can be combined with ovrInputState for complete hand controller information.
+ ovrPoseStatef HandPoses[2];
+
+ /// HandPoses status flags described by ovrStatusBits.
+ /// Only ovrStatus_OrientationTracked and ovrStatus_PositionTracked are reported.
+ unsigned int HandStatusFlags[2];
+
+ /// The pose of the origin captured during calibration.
+ /// Like all other poses here, this is expressed in the space set by ovr_RecenterTrackingOrigin,
+ /// and so will change every time that is called. This pose can be used to calculate
+ /// where the calibrated origin lands in the new recentered space.
+ /// If an application never calls ovr_RecenterTrackingOrigin, expect this value to be the identity
+ /// pose and as such will point respective origin based on ovrTrackingOrigin requested when
+ /// calling ovr_GetTrackingState.
+ ovrPosef CalibratedOrigin;
+
+} ovrTrackingState;
+
+
+/// Rendering information for each eye. Computed by ovr_GetRenderDesc() based on the
+/// specified FOV. Note that the rendering viewport is not included
+/// here as it can be specified separately and modified per frame by
+/// passing different Viewport values in the layer structure.
+///
+/// \see ovr_GetRenderDesc
+///
+typedef struct OVR_ALIGNAS(4) ovrEyeRenderDesc_
+{
+ ovrEyeType Eye; ///< The eye index to which this instance corresponds.
+ ovrFovPort Fov; ///< The field of view.
+ ovrRecti DistortedViewport; ///< Distortion viewport.
+ ovrVector2f PixelsPerTanAngleAtCenter; ///< How many display pixels will fit in tan(angle) = 1.
+ ovrVector3f HmdToEyeOffset; ///< Translation of each eye, in meters.
+} ovrEyeRenderDesc;
+
+
+/// Projection information for ovrLayerEyeFovDepth.
+///
+/// Use the utility function ovrTimewarpProjectionDesc_FromProjection to
+/// generate this structure from the application's projection matrix.
+///
+/// \see ovrLayerEyeFovDepth, ovrTimewarpProjectionDesc_FromProjection
+///
+typedef struct OVR_ALIGNAS(4) ovrTimewarpProjectionDesc_
+{
+ float Projection22; ///< Projection matrix element [2][2].
+ float Projection23; ///< Projection matrix element [2][3].
+ float Projection32; ///< Projection matrix element [3][2].
+} ovrTimewarpProjectionDesc;
+
+
+/// Contains the data necessary to properly calculate position info for various layer types.
+/// - HmdToEyeOffset is the same value pair provided in ovrEyeRenderDesc.
+/// - HmdSpaceToWorldScaleInMeters is used to scale player motion into in-application units.
+/// In other words, it is how big an in-application unit is in the player's physical meters.
+/// For example, if the application uses inches as its units then HmdSpaceToWorldScaleInMeters would be 0.0254.
+/// Note that if you are scaling the player in size, this must also scale. So if your application
+/// units are inches, but you're shrinking the player to half their normal size, then
+/// HmdSpaceToWorldScaleInMeters would be 0.0254*2.0.
+///
+/// \see ovrEyeRenderDesc, ovr_SubmitFrame
+///
+typedef struct OVR_ALIGNAS(4) ovrViewScaleDesc_
+{
+ ovrVector3f HmdToEyeOffset[ovrEye_Count]; ///< Translation of each eye.
+ float HmdSpaceToWorldScaleInMeters; ///< Ratio of viewer units to meter units.
+} ovrViewScaleDesc;
+
+
+//-----------------------------------------------------------------------------------
+// ***** Platform-independent Rendering Configuration
+
+/// The type of texture resource.
+///
+/// \see ovrTextureSwapChainDesc
+///
+typedef enum ovrTextureType_
+{
+ ovrTexture_2D, ///< 2D textures.
+ ovrTexture_2D_External, ///< External 2D texture. Not used on PC
+ ovrTexture_Cube, ///< Cube maps. Not currently supported on PC.
+ ovrTexture_Count,
+ ovrTexture_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrTextureType;
+
+/// The bindings required for texture swap chain.
+///
+/// All texture swap chains are automatically bindable as shader
+/// input resources since the Oculus runtime needs this to read them.
+///
+/// \see ovrTextureSwapChainDesc
+///
+typedef enum ovrTextureBindFlags_
+{
+ ovrTextureBind_None,
+ ovrTextureBind_DX_RenderTarget = 0x0001, ///< The application can write into the chain with pixel shader
+ ovrTextureBind_DX_UnorderedAccess = 0x0002, ///< The application can write to the chain with compute shader
+ ovrTextureBind_DX_DepthStencil = 0x0004, ///< The chain buffers can be bound as depth and/or stencil buffers
+
+ ovrTextureBind_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrTextureBindFlags;
+
+/// The format of a texture.
+///
+/// \see ovrTextureSwapChainDesc
+///
+typedef enum ovrTextureFormat_
+{
+ OVR_FORMAT_UNKNOWN,
+ OVR_FORMAT_B5G6R5_UNORM, ///< Not currently supported on PC. Would require a DirectX 11.1 device.
+ OVR_FORMAT_B5G5R5A1_UNORM, ///< Not currently supported on PC. Would require a DirectX 11.1 device.
+ OVR_FORMAT_B4G4R4A4_UNORM, ///< Not currently supported on PC. Would require a DirectX 11.1 device.
+ OVR_FORMAT_R8G8B8A8_UNORM,
+ OVR_FORMAT_R8G8B8A8_UNORM_SRGB,
+ OVR_FORMAT_B8G8R8A8_UNORM,
+ OVR_FORMAT_B8G8R8A8_UNORM_SRGB, ///< Not supported for OpenGL applications
+ OVR_FORMAT_B8G8R8X8_UNORM, ///< Not supported for OpenGL applications
+ OVR_FORMAT_B8G8R8X8_UNORM_SRGB, ///< Not supported for OpenGL applications
+ OVR_FORMAT_R16G16B16A16_FLOAT,
+ OVR_FORMAT_D16_UNORM,
+ OVR_FORMAT_D24_UNORM_S8_UINT,
+ OVR_FORMAT_D32_FLOAT,
+ OVR_FORMAT_D32_FLOAT_S8X24_UINT,
+
+ // Added in 1.5 compressed formats can be used for static layers
+ OVR_FORMAT_BC1_UNORM,
+ OVR_FORMAT_BC1_UNORM_SRGB,
+ OVR_FORMAT_BC2_UNORM,
+ OVR_FORMAT_BC2_UNORM_SRGB,
+ OVR_FORMAT_BC3_UNORM,
+ OVR_FORMAT_BC3_UNORM_SRGB,
+ OVR_FORMAT_BC6H_UF16,
+ OVR_FORMAT_BC6H_SF16,
+ OVR_FORMAT_BC7_UNORM,
+ OVR_FORMAT_BC7_UNORM_SRGB,
+
+ OVR_FORMAT_ENUMSIZE = 0x7fffffff ///< \internal Force type int32_t.
+} ovrTextureFormat;
+
+/// Misc flags overriding particular
+/// behaviors of a texture swap chain
+///
+/// \see ovrTextureSwapChainDesc
+///
+typedef enum ovrTextureMiscFlags_
+{
+ ovrTextureMisc_None,
+
+ /// DX only: The underlying texture is created with a TYPELESS equivalent of the
+ /// format specified in the texture desc. The SDK will still access the
+ /// texture using the format specified in the texture desc, but the app can
+ /// create views with different formats if this is specified.
+ ovrTextureMisc_DX_Typeless = 0x0001,
+
+ /// DX only: Allow generation of the mip chain on the GPU via the GenerateMips
+ /// call. This flag requires that RenderTarget binding also be specified.
+ ovrTextureMisc_AllowGenerateMips = 0x0002,
+
+ /// Texture swap chain contains protected content, and requires
+ /// HDCP connection in order to display to HMD. Also prevents
+ /// mirroring or other redirection of any frame containing this contents
+ ovrTextureMisc_ProtectedContent = 0x0004,
+
+ ovrTextureMisc_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrTextureFlags;
+
+/// Description used to create a texture swap chain.
+///
+/// \see ovr_CreateTextureSwapChainDX
+/// \see ovr_CreateTextureSwapChainGL
+///
+typedef struct ovrTextureSwapChainDesc_
+{
+ ovrTextureType Type;
+ ovrTextureFormat Format;
+ int ArraySize; ///< Only supported with ovrTexture_2D. Not supported on PC at this time.
+ int Width;
+ int Height;
+ int MipLevels;
+ int SampleCount; ///< Current only supported on depth textures
+ ovrBool StaticImage; ///< Not buffered in a chain. For images that don't change
+ unsigned int MiscFlags; ///< ovrTextureFlags
+ unsigned int BindFlags; ///< ovrTextureBindFlags. Not used for GL.
+} ovrTextureSwapChainDesc;
+
+/// Description used to create a mirror texture.
+///
+/// \see ovr_CreateMirrorTextureDX
+/// \see ovr_CreateMirrorTextureGL
+///
+typedef struct ovrMirrorTextureDesc_
+{
+ ovrTextureFormat Format;
+ int Width;
+ int Height;
+ unsigned int MiscFlags; ///< ovrTextureFlags
+} ovrMirrorTextureDesc;
+
+typedef struct ovrTextureSwapChainData* ovrTextureSwapChain;
+typedef struct ovrMirrorTextureData* ovrMirrorTexture;
+
+//-----------------------------------------------------------------------------------
+
+/// Describes button input types.
+/// Button inputs are combined; that is they will be reported as pressed if they are
+/// pressed on either one of the two devices.
+/// The ovrButton_Up/Down/Left/Right map to both XBox D-Pad and directional buttons.
+/// The ovrButton_Enter and ovrButton_Return map to Start and Back controller buttons, respectively.
+typedef enum ovrButton_
+{
+ ovrButton_A = 0x00000001,
+ ovrButton_B = 0x00000002,
+ ovrButton_RThumb = 0x00000004,
+ ovrButton_RShoulder = 0x00000008,
+
+ ovrButton_X = 0x00000100,
+ ovrButton_Y = 0x00000200,
+ ovrButton_LThumb = 0x00000400,
+ ovrButton_LShoulder = 0x00000800,
+
+ // Navigation through DPad.
+ ovrButton_Up = 0x00010000,
+ ovrButton_Down = 0x00020000,
+ ovrButton_Left = 0x00040000,
+ ovrButton_Right = 0x00080000,
+ ovrButton_Enter = 0x00100000, // Start on XBox controller.
+ ovrButton_Back = 0x00200000, // Back on Xbox controller.
+ ovrButton_VolUp = 0x00400000, // only supported by Remote.
+ ovrButton_VolDown = 0x00800000, // only supported by Remote.
+ ovrButton_Home = 0x01000000,
+ ovrButton_Private = ovrButton_VolUp | ovrButton_VolDown | ovrButton_Home,
+
+ // Bit mask of all buttons on the right Touch controller
+ ovrButton_RMask = ovrButton_A | ovrButton_B | ovrButton_RThumb | ovrButton_RShoulder,
+
+ // Bit mask of all buttons on the left Touch controller
+ ovrButton_LMask = ovrButton_X | ovrButton_Y | ovrButton_LThumb | ovrButton_LShoulder |
+ ovrButton_Enter,
+
+
+ ovrButton_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrButton;
+
+/// Describes touch input types.
+/// These values map to capacitive touch values reported ovrInputState::Touch.
+/// Some of these values are mapped to button bits for consistency.
+typedef enum ovrTouch_
+{
+ ovrTouch_A = ovrButton_A,
+ ovrTouch_B = ovrButton_B,
+ ovrTouch_RThumb = ovrButton_RThumb,
+ ovrTouch_RThumbRest = 0x00000008,
+ ovrTouch_RIndexTrigger = 0x00000010,
+
+ // Bit mask of all the button touches on the right controller
+ ovrTouch_RButtonMask = ovrTouch_A | ovrTouch_B | ovrTouch_RThumb | ovrTouch_RThumbRest | ovrTouch_RIndexTrigger,
+
+ ovrTouch_X = ovrButton_X,
+ ovrTouch_Y = ovrButton_Y,
+ ovrTouch_LThumb = ovrButton_LThumb,
+ ovrTouch_LThumbRest = 0x00000800,
+ ovrTouch_LIndexTrigger = 0x00001000,
+
+ // Bit mask of all the button touches on the left controller
+ ovrTouch_LButtonMask = ovrTouch_X | ovrTouch_Y | ovrTouch_LThumb | ovrTouch_LThumbRest | ovrTouch_LIndexTrigger,
+
+ // Finger pose state
+ // Derived internally based on distance, proximity to sensors and filtering.
+ ovrTouch_RIndexPointing = 0x00000020,
+ ovrTouch_RThumbUp = 0x00000040,
+
+ // Bit mask of all right controller poses
+ ovrTouch_RPoseMask = ovrTouch_RIndexPointing | ovrTouch_RThumbUp,
+
+ ovrTouch_LIndexPointing = 0x00002000,
+ ovrTouch_LThumbUp = 0x00004000,
+
+ // Bit mask of all left controller poses
+ ovrTouch_LPoseMask = ovrTouch_LIndexPointing | ovrTouch_LThumbUp,
+
+ ovrTouch_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrTouch;
+
+/// Describes the Touch Haptics engine.
+/// Currently, those values will NOT change during a session.
+typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrTouchHapticsDesc_
+{
+ // Haptics engine frequency/sample-rate, sample time in seconds equals 1.0/sampleRateHz
+ int SampleRateHz;
+ // Size of each Haptics sample, sample value range is [0, 2^(Bytes*8)-1]
+ int SampleSizeInBytes;
+
+ // Queue size that would guarantee Haptics engine would not starve for data
+ // Make sure size doesn't drop below it for best results
+ int QueueMinSizeToAvoidStarvation;
+
+ // Minimum, Maximum and Optimal number of samples that can be sent to Haptics through ovr_SubmitControllerVibration
+ int SubmitMinSamples;
+ int SubmitMaxSamples;
+ int SubmitOptimalSamples;
+} ovrTouchHapticsDesc;
+
+/// Specifies which controller is connected; multiple can be connected at once.
+typedef enum ovrControllerType_
+{
+ ovrControllerType_None = 0x00,
+ ovrControllerType_LTouch = 0x01,
+ ovrControllerType_RTouch = 0x02,
+ ovrControllerType_Touch = 0x03,
+ ovrControllerType_Remote = 0x04,
+ ovrControllerType_XBox = 0x10,
+
+ ovrControllerType_Active = 0xff, ///< Operate on or query whichever controller is active.
+
+ ovrControllerType_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrControllerType;
+
+/// Haptics buffer submit mode
+typedef enum ovrHapticsBufferSubmitMode_
+{
+ // Enqueue buffer for later playback
+ ovrHapticsBufferSubmit_Enqueue
+} ovrHapticsBufferSubmitMode;
+
+/// Haptics buffer descriptor, contains amplitude samples used for Touch vibration
+typedef struct ovrHapticsBuffer_
+{
+ const void* Samples;
+ int SamplesCount;
+ ovrHapticsBufferSubmitMode SubmitMode;
+} ovrHapticsBuffer;
+
+/// State of the Haptics playback for Touch vibration
+typedef struct ovrHapticsPlaybackState_
+{
+ // Remaining space available to queue more samples
+ int RemainingQueueSpace;
+
+ // Number of samples currently queued
+ int SamplesQueued;
+} ovrHapticsPlaybackState;
+
+/// Position tracked devices
+typedef enum ovrTrackedDeviceType_
+{
+ ovrTrackedDevice_HMD = 0x0001,
+ ovrTrackedDevice_LTouch = 0x0002,
+ ovrTrackedDevice_RTouch = 0x0004,
+ ovrTrackedDevice_Touch = 0x0006,
+ ovrTrackedDevice_All = 0xFFFF,
+} ovrTrackedDeviceType;
+
+/// Provides names for the left and right hand array indexes.
+///
+/// \see ovrInputState, ovrTrackingState
+///
+typedef enum ovrHandType_
+{
+ ovrHand_Left = 0,
+ ovrHand_Right = 1,
+ ovrHand_Count = 2,
+ ovrHand_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrHandType;
+
+
+
+/// ovrInputState describes the complete controller input state, including Oculus Touch,
+/// and XBox gamepad. If multiple inputs are connected and used at the same time,
+/// their inputs are combined.
+typedef struct ovrInputState_
+{
+ /// System type when the controller state was last updated.
+ double TimeInSeconds;
+
+ /// Values for buttons described by ovrButton.
+ unsigned int Buttons;
+
+ /// Touch values for buttons and sensors as described by ovrTouch.
+ unsigned int Touches;
+
+ /// Left and right finger trigger values (ovrHand_Left and ovrHand_Right), in the range 0.0 to 1.0f.
+ /// Returns 0 if the value would otherwise be less than 0.1176, for ovrControllerType_XBox
+ float IndexTrigger[ovrHand_Count];
+
+ /// Left and right hand trigger values (ovrHand_Left and ovrHand_Right), in the range 0.0 to 1.0f.
+ float HandTrigger[ovrHand_Count];
+
+ /// Horizontal and vertical thumbstick axis values (ovrHand_Left and ovrHand_Right), in the range -1.0f to 1.0f.
+ /// Returns a deadzone (value 0) per each axis if the value on that axis would otherwise have been between -.2746 to +.2746, for ovrControllerType_XBox
+ ovrVector2f Thumbstick[ovrHand_Count];
+
+ /// The type of the controller this state is for.
+ ovrControllerType ControllerType;
+
+ /// Left and right finger trigger values (ovrHand_Left and ovrHand_Right), in the range 0.0 to 1.0f.
+ /// Does not apply a deadzone
+ /// Added in 1.7
+ float IndexTriggerNoDeadzone[ovrHand_Count];
+
+ /// Left and right hand trigger values (ovrHand_Left and ovrHand_Right), in the range 0.0 to 1.0f.
+ /// Does not apply a deadzone
+ /// Added in 1.7
+ float HandTriggerNoDeadzone[ovrHand_Count];
+
+ /// Horizontal and vertical thumbstick axis values (ovrHand_Left and ovrHand_Right), in the range -1.0f to 1.0f
+ /// Does not apply a deadzone
+ /// Added in 1.7
+ ovrVector2f ThumbstickNoDeadzone[ovrHand_Count];
+} ovrInputState;
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Initialize structures
+
+/// Initialization flags.
+///
+/// \see ovrInitParams, ovr_Initialize
+///
+typedef enum ovrInitFlags_
+{
+ /// When a debug library is requested, a slower debugging version of the library will
+ /// run which can be used to help solve problems in the library and debug application code.
+ ovrInit_Debug = 0x00000001,
+
+ /// When a version is requested, the LibOVR runtime respects the RequestedMinorVersion
+ /// field and verifies that the RequestedMinorVersion is supported.
+ ovrInit_RequestVersion = 0x00000004,
+
+ // These bits are writable by user code.
+ ovrinit_WritableBits = 0x00ffffff,
+
+ ovrInit_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrInitFlags;
+
+
+/// Logging levels
+///
+/// \see ovrInitParams, ovrLogCallback
+///
+typedef enum ovrLogLevel_
+{
+ ovrLogLevel_Debug = 0, ///< Debug-level log event.
+ ovrLogLevel_Info = 1, ///< Info-level log event.
+ ovrLogLevel_Error = 2, ///< Error-level log event.
+
+ ovrLogLevel_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrLogLevel;
+
+
+/// Signature of the logging callback function pointer type.
+///
+/// \param[in] userData is an arbitrary value specified by the user of ovrInitParams.
+/// \param[in] level is one of the ovrLogLevel constants.
+/// \param[in] message is a UTF8-encoded null-terminated string.
+/// \see ovrInitParams, ovrLogLevel, ovr_Initialize
+///
+typedef void (OVR_CDECL* ovrLogCallback)(uintptr_t userData, int level, const char* message);
+
+
+/// Parameters for ovr_Initialize.
+///
+/// \see ovr_Initialize
+///
+typedef struct OVR_ALIGNAS(8) ovrInitParams_
+{
+ /// Flags from ovrInitFlags to override default behavior.
+ /// Use 0 for the defaults.
+ uint32_t Flags;
+
+ /// Requests a specific minimum minor version of the LibOVR runtime.
+ /// Flags must include ovrInit_RequestVersion or this will be ignored
+ /// and OVR_MINOR_VERSION will be used.
+ uint32_t RequestedMinorVersion;
+
+ /// User-supplied log callback function, which may be called at any time
+ /// asynchronously from multiple threads until ovr_Shutdown completes.
+ /// Use NULL to specify no log callback.
+ ovrLogCallback LogCallback;
+
+ /// User-supplied data which is passed as-is to LogCallback. Typically this
+ /// is used to store an application-specific pointer which is read in the
+ /// callback function.
+ uintptr_t UserData;
+
+ /// Relative number of milliseconds to wait for a connection to the server
+ /// before failing. Use 0 for the default timeout.
+ uint32_t ConnectionTimeoutMS;
+
+ OVR_ON64(OVR_UNUSED_STRUCT_PAD(pad0, 4)) ///< \internal
+
+} ovrInitParams;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(OVR_EXPORTING_CAPI)
+
+// -----------------------------------------------------------------------------------
+// ***** API Interfaces
+
+/// Initializes LibOVR
+///
+/// Initialize LibOVR for application usage. This includes finding and loading the LibOVRRT
+/// shared library. No LibOVR API functions, other than ovr_GetLastErrorInfo and ovr_Detect, can
+/// be called unless ovr_Initialize succeeds. A successful call to ovr_Initialize must be eventually
+/// followed by a call to ovr_Shutdown. ovr_Initialize calls are idempotent.
+/// Calling ovr_Initialize twice does not require two matching calls to ovr_Shutdown.
+/// If already initialized, the return value is ovr_Success.
+///
+/// LibOVRRT shared library search order:
+/// -# Current working directory (often the same as the application directory).
+/// -# Module directory (usually the same as the application directory,
+/// but not if the module is a separate shared library).
+/// -# Application directory
+/// -# Development directory (only if OVR_ENABLE_DEVELOPER_SEARCH is enabled,
+/// which is off by default).
+/// -# Standard OS shared library search location(s) (OS-specific).
+///
+/// \param params Specifies custom initialization options. May be NULL to indicate default options.
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information. Example failed results include:
+/// - ovrError_Initialize: Generic initialization error.
+/// - ovrError_LibLoad: Couldn't load LibOVRRT.
+/// - ovrError_LibVersion: LibOVRRT version incompatibility.
+/// - ovrError_ServiceConnection: Couldn't connect to the OVR Service.
+/// - ovrError_ServiceVersion: OVR Service version incompatibility.
+/// - ovrError_IncompatibleOS: The operating system version is incompatible.
+/// - ovrError_DisplayInit: Unable to initialize the HMD display.
+/// - ovrError_ServerStart: Unable to start the server. Is it already running?
+/// - ovrError_Reinitialization: Attempted to re-initialize with a different version.
+///
+/// <b>Example code</b>
+/// \code{.cpp}
+/// ovrResult result = ovr_Initialize(NULL);
+/// if(OVR_FAILURE(result)) {
+/// ovrErrorInfo errorInfo;
+/// ovr_GetLastErrorInfo(&errorInfo);
+/// DebugLog("ovr_Initialize failed: %s", errorInfo.ErrorString);
+/// return false;
+/// }
+/// [...]
+/// \endcode
+///
+/// \see ovr_Shutdown
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_Initialize(const ovrInitParams* params);
+
+
+/// Shuts down LibOVR
+///
+/// A successful call to ovr_Initialize must be eventually matched by a call to ovr_Shutdown.
+/// After calling ovr_Shutdown, no LibOVR functions can be called except ovr_GetLastErrorInfo
+/// or another ovr_Initialize. ovr_Shutdown invalidates all pointers, references, and created objects
+/// previously returned by LibOVR functions. The LibOVRRT shared library can be unloaded by
+/// ovr_Shutdown.
+///
+/// \see ovr_Initialize
+///
+OVR_PUBLIC_FUNCTION(void) ovr_Shutdown();
+
+/// Returns information about the most recent failed return value by the
+/// current thread for this library.
+///
+/// This function itself can never generate an error.
+/// The last error is never cleared by LibOVR, but will be overwritten by new errors.
+/// Do not use this call to determine if there was an error in the last API
+/// call as successful API calls don't clear the last ovrErrorInfo.
+/// To avoid any inconsistency, ovr_GetLastErrorInfo should be called immediately
+/// after an API function that returned a failed ovrResult, with no other API
+/// functions called in the interim.
+///
+/// \param[out] errorInfo The last ovrErrorInfo for the current thread.
+///
+/// \see ovrErrorInfo
+///
+OVR_PUBLIC_FUNCTION(void) ovr_GetLastErrorInfo(ovrErrorInfo* errorInfo);
+
+
+/// Returns the version string representing the LibOVRRT version.
+///
+/// The returned string pointer is valid until the next call to ovr_Shutdown.
+///
+/// Note that the returned version string doesn't necessarily match the current
+/// OVR_MAJOR_VERSION, etc., as the returned string refers to the LibOVRRT shared
+/// library version and not the locally compiled interface version.
+///
+/// The format of this string is subject to change in future versions and its contents
+/// should not be interpreted.
+///
+/// \return Returns a UTF8-encoded null-terminated version string.
+///
+OVR_PUBLIC_FUNCTION(const char*) ovr_GetVersionString();
+
+
+/// Writes a message string to the LibOVR tracing mechanism (if enabled).
+///
+/// This message will be passed back to the application via the ovrLogCallback if
+/// it was registered.
+///
+/// \param[in] level One of the ovrLogLevel constants.
+/// \param[in] message A UTF8-encoded null-terminated string.
+/// \return returns the strlen of the message or a negative value if the message is too large.
+///
+/// \see ovrLogLevel, ovrLogCallback
+///
+OVR_PUBLIC_FUNCTION(int) ovr_TraceMessage(int level, const char* message);
+
+
+/// Identify client application info.
+///
+/// The string is one or more newline-delimited lines of optional info
+/// indicating engine name, engine version, engine plugin name, engine plugin
+/// version, engine editor. The order of the lines is not relevant. Individual
+/// lines are optional. A newline is not necessary at the end of the last line.
+/// Call after ovr_Initialize and before the first call to ovr_Create.
+/// Each value is limited to 20 characters. Key names such as 'EngineName:'
+/// 'EngineVersion:' do not count towards this limit.
+///
+/// \param[in] identity Specifies one or more newline-delimited lines of optional info:
+/// EngineName: %s\n
+/// EngineVersion: %s\n
+/// EnginePluginName: %s\n
+/// EnginePluginVersion: %s\n
+/// EngineEditor: <boolean> ('true' or 'false')\n
+///
+/// <b>Example code</b>
+/// \code{.cpp}
+/// ovr_IdentifyClient("EngineName: Unity\n"
+/// "EngineVersion: 5.3.3\n"
+/// "EnginePluginName: OVRPlugin\n"
+/// "EnginePluginVersion: 1.2.0\n"
+/// "EngineEditor: true");
+/// \endcode
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_IdentifyClient(const char* identity);
+
+
+//-------------------------------------------------------------------------------------
+/// @name HMD Management
+///
+/// Handles the enumeration, creation, destruction, and properties of an HMD (head-mounted display).
+///@{
+
+
+/// Returns information about the current HMD.
+///
+/// ovr_Initialize must have first been called in order for this to succeed, otherwise ovrHmdDesc::Type
+/// will be reported as ovrHmd_None.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create, else NULL in which
+/// case this function detects whether an HMD is present and returns its info if so.
+///
+/// \return Returns an ovrHmdDesc. If the hmd is NULL and ovrHmdDesc::Type is ovrHmd_None then
+/// no HMD is present.
+///
+OVR_PUBLIC_FUNCTION(ovrHmdDesc) ovr_GetHmdDesc(ovrSession session);
+
+
+/// Returns the number of sensors.
+///
+/// The number of sensors may change at any time, so this function should be called before use
+/// as opposed to once on startup.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+///
+/// \return Returns unsigned int count.
+///
+OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetTrackerCount(ovrSession session);
+
+
+/// Returns a given sensor description.
+///
+/// It's possible that sensor desc [0] may indicate a unconnnected or non-pose tracked sensor, but
+/// sensor desc [1] may be connected.
+///
+/// ovr_Initialize must have first been called in order for this to succeed, otherwise the returned
+/// trackerDescArray will be zero-initialized. The data returned by this function can change at runtime.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+///
+/// \param[in] trackerDescIndex Specifies a sensor index. The valid indexes are in the range of 0 to
+/// the sensor count returned by ovr_GetTrackerCount.
+///
+/// \return Returns ovrTrackerDesc. An empty ovrTrackerDesc will be returned if trackerDescIndex is out of range.
+///
+/// \see ovrTrackerDesc, ovr_GetTrackerCount
+///
+OVR_PUBLIC_FUNCTION(ovrTrackerDesc) ovr_GetTrackerDesc(ovrSession session, unsigned int trackerDescIndex);
+
+
+/// Creates a handle to a VR session.
+///
+/// Upon success the returned ovrSession must be eventually freed with ovr_Destroy when it is no longer needed.
+/// A second call to ovr_Create will result in an error return value if the previous session has not been destroyed.
+///
+/// \param[out] pSession Provides a pointer to an ovrSession which will be written to upon success.
+/// \param[out] luid Provides a system specific graphics adapter identifier that locates which
+/// graphics adapter has the HMD attached. This must match the adapter used by the application
+/// or no rendering output will be possible. This is important for stability on multi-adapter systems. An
+/// application that simply chooses the default adapter will not run reliably on multi-adapter systems.
+/// \return Returns an ovrResult indicating success or failure. Upon failure
+/// the returned ovrSession will be NULL.
+///
+/// <b>Example code</b>
+/// \code{.cpp}
+/// ovrSession session;
+/// ovrGraphicsLuid luid;
+/// ovrResult result = ovr_Create(&session, &luid);
+/// if(OVR_FAILURE(result))
+/// ...
+/// \endcode
+///
+/// \see ovr_Destroy
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_Create(ovrSession* pSession, ovrGraphicsLuid* pLuid);
+
+
+/// Destroys the session.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \see ovr_Create
+///
+OVR_PUBLIC_FUNCTION(void) ovr_Destroy(ovrSession session);
+
+#endif // !defined(OVR_EXPORTING_CAPI)
+
+/// Specifies status information for the current session.
+///
+/// \see ovr_GetSessionStatus
+///
+typedef struct ovrSessionStatus_
+{
+ ovrBool IsVisible; ///< True if the process has VR focus and thus is visible in the HMD.
+ ovrBool HmdPresent; ///< True if an HMD is present.
+ ovrBool HmdMounted; ///< True if the HMD is on the user's head.
+ ovrBool DisplayLost; ///< True if the session is in a display-lost state. See ovr_SubmitFrame.
+ ovrBool ShouldQuit; ///< True if the application should initiate shutdown.
+ ovrBool ShouldRecenter; ///< True if UX has requested re-centering. Must call ovr_ClearShouldRecenterFlag or ovr_RecenterTrackingOrigin.
+}ovrSessionStatus;
+
+#if !defined(OVR_EXPORTING_CAPI)
+
+/// Returns status information for the application.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[out] sessionStatus Provides an ovrSessionStatus that is filled in.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of
+/// failure, use ovr_GetLastErrorInfo to get more information.
+// Return values include but aren't limited to:
+/// - ovrSuccess: Completed successfully.
+/// - ovrError_ServiceConnection: The service connection was lost and the application
+// must destroy the session.
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetSessionStatus(ovrSession session, ovrSessionStatus* sessionStatus);
+
+
+//@}
+
+
+
+//-------------------------------------------------------------------------------------
+/// @name Tracking
+///
+/// Tracking functions handle the position, orientation, and movement of the HMD in space.
+///
+/// All tracking interface functions are thread-safe, allowing tracking state to be sampled
+/// from different threads.
+///
+///@{
+
+
+
+/// Sets the tracking origin type
+///
+/// When the tracking origin is changed, all of the calls that either provide
+/// or accept ovrPosef will use the new tracking origin provided.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] origin Specifies an ovrTrackingOrigin to be used for all ovrPosef
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+/// \see ovrTrackingOrigin, ovr_GetTrackingOriginType
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_SetTrackingOriginType(ovrSession session, ovrTrackingOrigin origin);
+
+
+/// Gets the tracking origin state
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+///
+/// \return Returns the ovrTrackingOrigin that was either set by default, or previous set by the application.
+///
+/// \see ovrTrackingOrigin, ovr_SetTrackingOriginType
+OVR_PUBLIC_FUNCTION(ovrTrackingOrigin) ovr_GetTrackingOriginType(ovrSession session);
+
+
+/// Re-centers the sensor position and orientation.
+///
+/// This resets the (x,y,z) positional components and the yaw orientation component.
+/// The Roll and pitch orientation components are always determined by gravity and cannot
+/// be redefined. All future tracking will report values relative to this new reference position.
+/// If you are using ovrTrackerPoses then you will need to call ovr_GetTrackerPose after
+/// this, because the sensor position(s) will change as a result of this.
+///
+/// The headset cannot be facing vertically upward or downward but rather must be roughly
+/// level otherwise this function will fail with ovrError_InvalidHeadsetOrientation.
+///
+/// For more info, see the notes on each ovrTrackingOrigin enumeration to understand how
+/// recenter will vary slightly in its behavior based on the current ovrTrackingOrigin setting.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information. Return values include but aren't limited to:
+/// - ovrSuccess: Completed successfully.
+/// - ovrError_InvalidHeadsetOrientation: The headset was facing an invalid direction when
+/// attempting recentering, such as facing vertically.
+///
+/// \see ovrTrackingOrigin, ovr_GetTrackerPose
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_RecenterTrackingOrigin(ovrSession session);
+
+
+/// Clears the ShouldRecenter status bit in ovrSessionStatus.
+///
+/// Clears the ShouldRecenter status bit in ovrSessionStatus, allowing further recenter
+/// requests to be detected. Since this is automatically done by ovr_RecenterTrackingOrigin,
+/// this is only needs to be called when application is doing its own re-centering.
+OVR_PUBLIC_FUNCTION(void) ovr_ClearShouldRecenterFlag(ovrSession session);
+
+
+/// Returns tracking state reading based on the specified absolute system time.
+///
+/// Pass an absTime value of 0.0 to request the most recent sensor reading. In this case
+/// both PredictedPose and SamplePose will have the same value.
+///
+/// This may also be used for more refined timing of front buffer rendering logic, and so on.
+/// This may be called by multiple threads.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] absTime Specifies the absolute future time to predict the return
+/// ovrTrackingState value. Use 0 to request the most recent tracking state.
+/// \param[in] latencyMarker Specifies that this call is the point in time where
+/// the "App-to-Mid-Photon" latency timer starts from. If a given ovrLayer
+/// provides "SensorSampleTime", that will override the value stored here.
+/// \return Returns the ovrTrackingState that is predicted for the given absTime.
+///
+/// \see ovrTrackingState, ovr_GetEyePoses, ovr_GetTimeInSeconds
+///
+OVR_PUBLIC_FUNCTION(ovrTrackingState) ovr_GetTrackingState(ovrSession session, double absTime, ovrBool latencyMarker);
+
+
+
+/// Returns the ovrTrackerPose for the given sensor.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] trackerPoseIndex Index of the sensor being requested.
+///
+/// \return Returns the requested ovrTrackerPose. An empty ovrTrackerPose will be returned if trackerPoseIndex is out of range.
+///
+/// \see ovr_GetTrackerCount
+///
+OVR_PUBLIC_FUNCTION(ovrTrackerPose) ovr_GetTrackerPose(ovrSession session, unsigned int trackerPoseIndex);
+
+
+
+/// Returns the most recent input state for controllers, without positional tracking info.
+///
+/// \param[out] inputState Input state that will be filled in.
+/// \param[in] ovrControllerType Specifies which controller the input will be returned for.
+/// \return Returns ovrSuccess if the new state was successfully obtained.
+///
+/// \see ovrControllerType
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetInputState(ovrSession session, ovrControllerType controllerType, ovrInputState* inputState);
+
+
+/// Returns controller types connected to the system OR'ed together.
+///
+/// \return A bitmask of ovrControllerTypes connected to the system.
+///
+/// \see ovrControllerType
+///
+OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetConnectedControllerTypes(ovrSession session);
+
+/// Gets information about Haptics engine for the specified Touch controller.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] controllerType The controller to retrieve the information from.
+///
+/// \return Returns an ovrTouchHapticsDesc.
+///
+OVR_PUBLIC_FUNCTION(ovrTouchHapticsDesc) ovr_GetTouchHapticsDesc(ovrSession session, ovrControllerType controllerType);
+
+/// Sets constant vibration (with specified frequency and amplitude) to a controller.
+/// Note: ovr_SetControllerVibration cannot be used interchangeably with ovr_SubmitControllerVibration.
+///
+/// This method should be called periodically, vibration lasts for a maximum of 2.5 seconds.
+/// It's recommended to call this method once a second, calls will be rejected if called too frequently (over 30hz).
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] controllerType The controller to set the vibration to.
+/// \param[in] frequency Vibration frequency. Supported values are: 0.0 (disabled), 0.5 and 1.0. Non valid values will be clamped.
+/// \param[in] amplitude Vibration amplitude in the [0.0, 1.0] range.
+/// \return Returns ovrSuccess upon success.
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_SetControllerVibration(ovrSession session, ovrControllerType controllerType, float frequency, float amplitude);
+
+/// Submits a Haptics buffer (used for vibration) to Touch (only) controllers.
+/// Note: ovr_SubmitControllerVibration cannot be used interchangeably with ovr_SetControllerVibration.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] controllerType Controller where the Haptics buffer will be played.
+/// \param[in] buffer Haptics buffer containing amplitude samples to be played.
+/// \return Returns ovrSuccess upon success.
+/// \see ovrHapticsBuffer
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_SubmitControllerVibration(ovrSession session, ovrControllerType controllerType, const ovrHapticsBuffer* buffer);
+
+/// Gets the Haptics engine playback state of a specific Touch controller.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] controllerType Controller where the Haptics buffer wil be played.
+/// \param[in] outState State of the haptics engine.
+/// \return Returns ovrSuccess upon success.
+/// \see ovrHapticsPlaybackState
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetControllerVibrationState(ovrSession session, ovrControllerType controllerType, ovrHapticsPlaybackState* outState);
+
+
+#endif // !defined(OVR_EXPORTING_CAPI)
+
+//-------------------------------------------------------------------------------------
+// @name Layers
+//
+///@{
+
+
+/// Specifies the maximum number of layers supported by ovr_SubmitFrame.
+///
+/// /see ovr_SubmitFrame
+///
+enum {
+ ovrMaxLayerCount = 16
+};
+
+/// Describes layer types that can be passed to ovr_SubmitFrame.
+/// Each layer type has an associated struct, such as ovrLayerEyeFov.
+///
+/// \see ovrLayerHeader
+///
+typedef enum ovrLayerType_
+{
+ ovrLayerType_Disabled = 0, ///< Layer is disabled.
+ ovrLayerType_EyeFov = 1, ///< Described by ovrLayerEyeFov.
+ ovrLayerType_Quad = 3, ///< Described by ovrLayerQuad. Previously called ovrLayerType_QuadInWorld.
+ /// enum 4 used to be ovrLayerType_QuadHeadLocked. Instead, use ovrLayerType_Quad with ovrLayerFlag_HeadLocked.
+ ovrLayerType_EyeMatrix = 5, ///< Described by ovrLayerEyeMatrix.
+ ovrLayerType_EnumSize = 0x7fffffff ///< Force type int32_t.
+} ovrLayerType;
+
+
+/// Identifies flags used by ovrLayerHeader and which are passed to ovr_SubmitFrame.
+///
+/// \see ovrLayerHeader
+///
+typedef enum ovrLayerFlags_
+{
+ /// ovrLayerFlag_HighQuality enables 4x anisotropic sampling during the composition of the layer.
+ /// The benefits are mostly visible at the periphery for high-frequency & high-contrast visuals.
+ /// For best results consider combining this flag with an ovrTextureSwapChain that has mipmaps and
+ /// instead of using arbitrary sized textures, prefer texture sizes that are powers-of-two.
+ /// Actual rendered viewport and doesn't necessarily have to fill the whole texture.
+ ovrLayerFlag_HighQuality = 0x01,
+
+ /// ovrLayerFlag_TextureOriginAtBottomLeft: the opposite is TopLeft.
+ /// Generally this is false for D3D, true for OpenGL.
+ ovrLayerFlag_TextureOriginAtBottomLeft = 0x02,
+
+ /// Mark this surface as "headlocked", which means it is specified
+ /// relative to the HMD and moves with it, rather than being specified
+ /// relative to sensor/torso space and remaining still while the head moves.
+ /// What used to be ovrLayerType_QuadHeadLocked is now ovrLayerType_Quad plus this flag.
+ /// However the flag can be applied to any layer type to achieve a similar effect.
+ ovrLayerFlag_HeadLocked = 0x04
+
+} ovrLayerFlags;
+
+
+/// Defines properties shared by all ovrLayer structs, such as ovrLayerEyeFov.
+///
+/// ovrLayerHeader is used as a base member in these larger structs.
+/// This struct cannot be used by itself except for the case that Type is ovrLayerType_Disabled.
+///
+/// \see ovrLayerType, ovrLayerFlags
+///
+typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrLayerHeader_
+{
+ ovrLayerType Type; ///< Described by ovrLayerType.
+ unsigned Flags; ///< Described by ovrLayerFlags.
+} ovrLayerHeader;
+
+
+/// Describes a layer that specifies a monoscopic or stereoscopic view.
+/// This is the kind of layer that's typically used as layer 0 to ovr_SubmitFrame,
+/// as it is the kind of layer used to render a 3D stereoscopic view.
+///
+/// Three options exist with respect to mono/stereo texture usage:
+/// - ColorTexture[0] and ColorTexture[1] contain the left and right stereo renderings, respectively.
+/// Viewport[0] and Viewport[1] refer to ColorTexture[0] and ColorTexture[1], respectively.
+/// - ColorTexture[0] contains both the left and right renderings, ColorTexture[1] is NULL,
+/// and Viewport[0] and Viewport[1] refer to sub-rects with ColorTexture[0].
+/// - ColorTexture[0] contains a single monoscopic rendering, and Viewport[0] and
+/// Viewport[1] both refer to that rendering.
+///
+/// \see ovrTextureSwapChain, ovr_SubmitFrame
+///
+typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrLayerEyeFov_
+{
+ /// Header.Type must be ovrLayerType_EyeFov.
+ ovrLayerHeader Header;
+
+ /// ovrTextureSwapChains for the left and right eye respectively.
+ /// The second one of which can be NULL for cases described above.
+ ovrTextureSwapChain ColorTexture[ovrEye_Count];
+
+ /// Specifies the ColorTexture sub-rect UV coordinates.
+ /// Both Viewport[0] and Viewport[1] must be valid.
+ ovrRecti Viewport[ovrEye_Count];
+
+ /// The viewport field of view.
+ ovrFovPort Fov[ovrEye_Count];
+
+ /// Specifies the position and orientation of each eye view, with the position specified in meters.
+ /// RenderPose will typically be the value returned from ovr_CalcEyePoses,
+ /// but can be different in special cases if a different head pose is used for rendering.
+ ovrPosef RenderPose[ovrEye_Count];
+
+ /// Specifies the timestamp when the source ovrPosef (used in calculating RenderPose)
+ /// was sampled from the SDK. Typically retrieved by calling ovr_GetTimeInSeconds
+ /// around the instant the application calls ovr_GetTrackingState
+ /// The main purpose for this is to accurately track app tracking latency.
+ double SensorSampleTime;
+
+} ovrLayerEyeFov;
+
+
+
+
+/// Describes a layer that specifies a monoscopic or stereoscopic view.
+/// This uses a direct 3x4 matrix to map from view space to the UV coordinates.
+/// It is essentially the same thing as ovrLayerEyeFov but using a much
+/// lower level. This is mainly to provide compatibility with specific apps.
+/// Unless the application really requires this flexibility, it is usually better
+/// to use ovrLayerEyeFov.
+///
+/// Three options exist with respect to mono/stereo texture usage:
+/// - ColorTexture[0] and ColorTexture[1] contain the left and right stereo renderings, respectively.
+/// Viewport[0] and Viewport[1] refer to ColorTexture[0] and ColorTexture[1], respectively.
+/// - ColorTexture[0] contains both the left and right renderings, ColorTexture[1] is NULL,
+/// and Viewport[0] and Viewport[1] refer to sub-rects with ColorTexture[0].
+/// - ColorTexture[0] contains a single monoscopic rendering, and Viewport[0] and
+/// Viewport[1] both refer to that rendering.
+///
+/// \see ovrTextureSwapChain, ovr_SubmitFrame
+///
+typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrLayerEyeMatrix_
+{
+ /// Header.Type must be ovrLayerType_EyeMatrix.
+ ovrLayerHeader Header;
+
+ /// ovrTextureSwapChains for the left and right eye respectively.
+ /// The second one of which can be NULL for cases described above.
+ ovrTextureSwapChain ColorTexture[ovrEye_Count];
+
+ /// Specifies the ColorTexture sub-rect UV coordinates.
+ /// Both Viewport[0] and Viewport[1] must be valid.
+ ovrRecti Viewport[ovrEye_Count];
+
+ /// Specifies the position and orientation of each eye view, with the position specified in meters.
+ /// RenderPose will typically be the value returned from ovr_CalcEyePoses,
+ /// but can be different in special cases if a different head pose is used for rendering.
+ ovrPosef RenderPose[ovrEye_Count];
+
+ /// Specifies the mapping from a view-space vector
+ /// to a UV coordinate on the textures given above.
+ /// P = (x,y,z,1)*Matrix
+ /// TexU = P.x/P.z
+ /// TexV = P.y/P.z
+ ovrMatrix4f Matrix[ovrEye_Count];
+
+ /// Specifies the timestamp when the source ovrPosef (used in calculating RenderPose)
+ /// was sampled from the SDK. Typically retrieved by calling ovr_GetTimeInSeconds
+ /// around the instant the application calls ovr_GetTrackingState
+ /// The main purpose for this is to accurately track app tracking latency.
+ double SensorSampleTime;
+
+} ovrLayerEyeMatrix;
+
+
+
+
+
+/// Describes a layer of Quad type, which is a single quad in world or viewer space.
+/// It is used for ovrLayerType_Quad. This type of layer represents a single
+/// object placed in the world and not a stereo view of the world itself.
+///
+/// A typical use of ovrLayerType_Quad is to draw a television screen in a room
+/// that for some reason is more convenient to draw as a layer than as part of the main
+/// view in layer 0. For example, it could implement a 3D popup GUI that is drawn at a
+/// higher resolution than layer 0 to improve fidelity of the GUI.
+///
+/// Quad layers are visible from both sides; they are not back-face culled.
+///
+/// \see ovrTextureSwapChain, ovr_SubmitFrame
+///
+typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrLayerQuad_
+{
+ /// Header.Type must be ovrLayerType_Quad.
+ ovrLayerHeader Header;
+
+ /// Contains a single image, never with any stereo view.
+ ovrTextureSwapChain ColorTexture;
+
+ /// Specifies the ColorTexture sub-rect UV coordinates.
+ ovrRecti Viewport;
+
+ /// Specifies the orientation and position of the center point of a Quad layer type.
+ /// The supplied direction is the vector perpendicular to the quad.
+ /// The position is in real-world meters (not the application's virtual world,
+ /// the physical world the user is in) and is relative to the "zero" position
+ /// set by ovr_RecenterTrackingOrigin unless the ovrLayerFlag_HeadLocked flag is used.
+ ovrPosef QuadPoseCenter;
+
+ /// Width and height (respectively) of the quad in meters.
+ ovrVector2f QuadSize;
+
+} ovrLayerQuad;
+
+
+
+
+/// Union that combines ovrLayer types in a way that allows them
+/// to be used in a polymorphic way.
+typedef union ovrLayer_Union_
+{
+ ovrLayerHeader Header;
+ ovrLayerEyeFov EyeFov;
+ ovrLayerQuad Quad;
+} ovrLayer_Union;
+
+
+//@}
+
+#if !defined(OVR_EXPORTING_CAPI)
+
+/// @name SDK Distortion Rendering
+///
+/// All of rendering functions including the configure and frame functions
+/// are not thread safe. It is OK to use ConfigureRendering on one thread and handle
+/// frames on another thread, but explicit synchronization must be done since
+/// functions that depend on configured state are not reentrant.
+///
+/// These functions support rendering of distortion by the SDK.
+///
+//@{
+
+/// TextureSwapChain creation is rendering API-specific.
+/// ovr_CreateTextureSwapChainDX and ovr_CreateTextureSwapChainGL can be found in the
+/// rendering API-specific headers, such as OVR_CAPI_D3D.h and OVR_CAPI_GL.h
+
+/// Gets the number of buffers in an ovrTextureSwapChain.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] chain Specifies the ovrTextureSwapChain for which the length should be retrieved.
+/// \param[out] out_Length Returns the number of buffers in the specified chain.
+///
+/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error.
+///
+/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainLength(ovrSession session, ovrTextureSwapChain chain, int* out_Length);
+
+/// Gets the current index in an ovrTextureSwapChain.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] chain Specifies the ovrTextureSwapChain for which the index should be retrieved.
+/// \param[out] out_Index Returns the current (free) index in specified chain.
+///
+/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error.
+///
+/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainCurrentIndex(ovrSession session, ovrTextureSwapChain chain, int* out_Index);
+
+/// Gets the description of the buffers in an ovrTextureSwapChain
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] chain Specifies the ovrTextureSwapChain for which the description should be retrieved.
+/// \param[out] out_Desc Returns the description of the specified chain.
+///
+/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error.
+///
+/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainDesc(ovrSession session, ovrTextureSwapChain chain, ovrTextureSwapChainDesc* out_Desc);
+
+/// Commits any pending changes to an ovrTextureSwapChain, and advances its current index
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] chain Specifies the ovrTextureSwapChain to commit.
+///
+/// \note When Commit is called, the texture at the current index is considered ready for use by the
+/// runtime, and further writes to it should be avoided. The swap chain's current index is advanced,
+/// providing there's room in the chain. The next time the SDK dereferences this texture swap chain,
+/// it will synchronize with the app's graphics context and pick up the submitted index, opening up
+/// room in the swap chain for further commits.
+///
+/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error.
+/// Failures include but aren't limited to:
+/// - ovrError_TextureSwapChainFull: ovr_CommitTextureSwapChain was called too many times on a texture swapchain without calling submit to use the chain.
+///
+/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_CommitTextureSwapChain(ovrSession session, ovrTextureSwapChain chain);
+
+/// Destroys an ovrTextureSwapChain and frees all the resources associated with it.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] chain Specifies the ovrTextureSwapChain to destroy. If it is NULL then this function has no effect.
+///
+/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL
+///
+OVR_PUBLIC_FUNCTION(void) ovr_DestroyTextureSwapChain(ovrSession session, ovrTextureSwapChain chain);
+
+
+/// MirrorTexture creation is rendering API-specific.
+/// ovr_CreateMirrorTextureDX and ovr_CreateMirrorTextureGL can be found in the
+/// rendering API-specific headers, such as OVR_CAPI_D3D.h and OVR_CAPI_GL.h
+
+/// Destroys a mirror texture previously created by one of the mirror texture creation functions.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] mirrorTexture Specifies the ovrTexture to destroy. If it is NULL then this function has no effect.
+///
+/// \see ovr_CreateMirrorTextureDX, ovr_CreateMirrorTextureGL
+///
+OVR_PUBLIC_FUNCTION(void) ovr_DestroyMirrorTexture(ovrSession session, ovrMirrorTexture mirrorTexture);
+
+
+/// Calculates the recommended viewport size for rendering a given eye within the HMD
+/// with a given FOV cone.
+///
+/// Higher FOV will generally require larger textures to maintain quality.
+/// Apps packing multiple eye views together on the same texture should ensure there are
+/// at least 8 pixels of padding between them to prevent texture filtering and chromatic
+/// aberration causing images to leak between the two eye views.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] eye Specifies which eye (left or right) to calculate for.
+/// \param[in] fov Specifies the ovrFovPort to use.
+/// \param[in] pixelsPerDisplayPixel Specifies the ratio of the number of render target pixels
+/// to display pixels at the center of distortion. 1.0 is the default value. Lower
+/// values can improve performance, higher values give improved quality.
+///
+/// <b>Example code</b>
+/// \code{.cpp}
+/// ovrHmdDesc hmdDesc = ovr_GetHmdDesc(session);
+/// ovrSizei eyeSizeLeft = ovr_GetFovTextureSize(session, ovrEye_Left, hmdDesc.DefaultEyeFov[ovrEye_Left], 1.0f);
+/// ovrSizei eyeSizeRight = ovr_GetFovTextureSize(session, ovrEye_Right, hmdDesc.DefaultEyeFov[ovrEye_Right], 1.0f);
+/// \endcode
+///
+/// \return Returns the texture width and height size.
+///
+OVR_PUBLIC_FUNCTION(ovrSizei) ovr_GetFovTextureSize(ovrSession session, ovrEyeType eye, ovrFovPort fov,
+ float pixelsPerDisplayPixel);
+
+/// Computes the distortion viewport, view adjust, and other rendering parameters for
+/// the specified eye.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] eyeType Specifies which eye (left or right) for which to perform calculations.
+/// \param[in] fov Specifies the ovrFovPort to use.
+///
+/// \return Returns the computed ovrEyeRenderDesc for the given eyeType and field of view.
+///
+/// \see ovrEyeRenderDesc
+///
+OVR_PUBLIC_FUNCTION(ovrEyeRenderDesc) ovr_GetRenderDesc(ovrSession session,
+ ovrEyeType eyeType, ovrFovPort fov);
+
+/// Submits layers for distortion and display.
+///
+/// ovr_SubmitFrame triggers distortion and processing which might happen asynchronously.
+/// The function will return when there is room in the submission queue and surfaces
+/// are available. Distortion might or might not have completed.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+///
+/// \param[in] frameIndex Specifies the targeted application frame index, or 0 to refer to one frame
+/// after the last time ovr_SubmitFrame was called.
+///
+/// \param[in] viewScaleDesc Provides additional information needed only if layerPtrList contains
+/// an ovrLayerType_Quad. If NULL, a default version is used based on the current configuration and a 1.0 world scale.
+///
+/// \param[in] layerPtrList Specifies a list of ovrLayer pointers, which can include NULL entries to
+/// indicate that any previously shown layer at that index is to not be displayed.
+/// Each layer header must be a part of a layer structure such as ovrLayerEyeFov or ovrLayerQuad,
+/// with Header.Type identifying its type. A NULL layerPtrList entry in the array indicates the
+// absence of the given layer.
+///
+/// \param[in] layerCount Indicates the number of valid elements in layerPtrList. The maximum
+/// supported layerCount is not currently specified, but may be specified in a future version.
+///
+/// - Layers are drawn in the order they are specified in the array, regardless of the layer type.
+///
+/// - Layers are not remembered between successive calls to ovr_SubmitFrame. A layer must be
+/// specified in every call to ovr_SubmitFrame or it won't be displayed.
+///
+/// - If a layerPtrList entry that was specified in a previous call to ovr_SubmitFrame is
+/// passed as NULL or is of type ovrLayerType_Disabled, that layer is no longer displayed.
+///
+/// - A layerPtrList entry can be of any layer type and multiple entries of the same layer type
+/// are allowed. No layerPtrList entry may be duplicated (i.e. the same pointer as an earlier entry).
+///
+/// <b>Example code</b>
+/// \code{.cpp}
+/// ovrLayerEyeFov layer0;
+/// ovrLayerQuad layer1;
+/// ...
+/// ovrLayerHeader* layers[2] = { &layer0.Header, &layer1.Header };
+/// ovrResult result = ovr_SubmitFrame(session, frameIndex, nullptr, layers, 2);
+/// \endcode
+///
+/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error and true
+/// upon success. Return values include but aren't limited to:
+/// - ovrSuccess: rendering completed successfully.
+/// - ovrSuccess_NotVisible: rendering completed successfully but was not displayed on the HMD,
+/// usually because another application currently has ownership of the HMD. Applications receiving
+/// this result should stop rendering new content, but continue to call ovr_SubmitFrame periodically
+/// until it returns a value other than ovrSuccess_NotVisible.
+/// - ovrError_DisplayLost: The session has become invalid (such as due to a device removal)
+/// and the shared resources need to be released (ovr_DestroyTextureSwapChain), the session needs to
+/// destroyed (ovr_Destroy) and recreated (ovr_Create), and new resources need to be created
+/// (ovr_CreateTextureSwapChainXXX). The application's existing private graphics resources do not
+/// need to be recreated unless the new ovr_Create call returns a different GraphicsLuid.
+/// - ovrError_TextureSwapChainInvalid: The ovrTextureSwapChain is in an incomplete or inconsistent state.
+/// Ensure ovr_CommitTextureSwapChain was called at least once first.
+///
+/// \see ovr_GetPredictedDisplayTime, ovrViewScaleDesc, ovrLayerHeader
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_SubmitFrame(ovrSession session, long long frameIndex,
+ const ovrViewScaleDesc* viewScaleDesc,
+ ovrLayerHeader const * const * layerPtrList, unsigned int layerCount);
+///@}
+
+#endif // !defined(OVR_EXPORTING_CAPI)
+
+//-------------------------------------------------------------------------------------
+/// @name Frame Timing
+///
+//@{
+
+
+#if !defined(OVR_EXPORTING_CAPI)
+
+/// Gets the time of the specified frame midpoint.
+///
+/// Predicts the time at which the given frame will be displayed. The predicted time
+/// is the middle of the time period during which the corresponding eye images will
+/// be displayed.
+///
+/// The application should increment frameIndex for each successively targeted frame,
+/// and pass that index to any relevant OVR functions that need to apply to the frame
+/// identified by that index.
+///
+/// This function is thread-safe and allows for multiple application threads to target
+/// their processing to the same displayed frame.
+///
+/// In the even that prediction fails due to various reasons (e.g. the display being off
+/// or app has yet to present any frames), the return value will be current CPU time.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] frameIndex Identifies the frame the caller wishes to target.
+/// A value of zero returns the next frame index.
+/// \return Returns the absolute frame midpoint time for the given frameIndex.
+/// \see ovr_GetTimeInSeconds
+///
+OVR_PUBLIC_FUNCTION(double) ovr_GetPredictedDisplayTime(ovrSession session, long long frameIndex);
+
+
+/// Returns global, absolute high-resolution time in seconds.
+///
+/// The time frame of reference for this function is not specified and should not be
+/// depended upon.
+///
+/// \return Returns seconds as a floating point value.
+/// \see ovrPoseStatef, ovrFrameTiming
+///
+OVR_PUBLIC_FUNCTION(double) ovr_GetTimeInSeconds();
+
+#endif // !defined(OVR_EXPORTING_CAPI)
+
+/// Performance HUD enables the HMD user to see information critical to
+/// the real-time operation of the VR application such as latency timing,
+/// and CPU & GPU performance metrics
+///
+/// App can toggle performance HUD modes as such:
+/// \code{.cpp}
+/// ovrPerfHudMode PerfHudMode = ovrPerfHud_LatencyTiming;
+/// ovr_SetInt(session, OVR_PERF_HUD_MODE, (int)PerfHudMode);
+/// \endcode
+///
+typedef enum ovrPerfHudMode_
+{
+ ovrPerfHud_Off = 0, ///< Turns off the performance HUD
+ ovrPerfHud_PerfSummary = 1, ///< Shows performance summary and headroom
+ ovrPerfHud_LatencyTiming = 2, ///< Shows latency related timing info
+ ovrPerfHud_AppRenderTiming = 3, ///< Shows render timing info for application
+ ovrPerfHud_CompRenderTiming = 4, ///< Shows render timing info for OVR compositor
+ ovrPerfHud_VersionInfo = 5, ///< Shows SDK & HMD version Info
+ ovrPerfHud_Count = 6, ///< \internal Count of enumerated elements.
+ ovrPerfHud_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrPerfHudMode;
+
+/// Layer HUD enables the HMD user to see information about a layer
+///
+/// App can toggle layer HUD modes as such:
+/// \code{.cpp}
+/// ovrLayerHudMode LayerHudMode = ovrLayerHud_Info;
+/// ovr_SetInt(session, OVR_LAYER_HUD_MODE, (int)LayerHudMode);
+/// \endcode
+///
+typedef enum ovrLayerHudMode_
+{
+ ovrLayerHud_Off = 0, ///< Turns off the layer HUD
+ ovrLayerHud_Info = 1, ///< Shows info about a specific layer
+ ovrLayerHud_EnumSize = 0x7fffffff
+} ovrLayerHudMode;
+
+///@}
+
+/// Debug HUD is provided to help developers gauge and debug the fidelity of their app's
+/// stereo rendering characteristics. Using the provided quad and crosshair guides,
+/// the developer can verify various aspects such as VR tracking units (e.g. meters),
+/// stereo camera-parallax properties (e.g. making sure objects at infinity are rendered
+/// with the proper separation), measuring VR geometry sizes and distances and more.
+///
+/// App can toggle the debug HUD modes as such:
+/// \code{.cpp}
+/// ovrDebugHudStereoMode DebugHudMode = ovrDebugHudStereo_QuadWithCrosshair;
+/// ovr_SetInt(session, OVR_DEBUG_HUD_STEREO_MODE, (int)DebugHudMode);
+/// \endcode
+///
+/// The app can modify the visual properties of the stereo guide (i.e. quad, crosshair)
+/// using the ovr_SetFloatArray function. For a list of tweakable properties,
+/// see the OVR_DEBUG_HUD_STEREO_GUIDE_* keys in the OVR_CAPI_Keys.h header file.
+typedef enum ovrDebugHudStereoMode_
+{
+ ovrDebugHudStereo_Off = 0, ///< Turns off the Stereo Debug HUD
+ ovrDebugHudStereo_Quad = 1, ///< Renders Quad in world for Stereo Debugging
+ ovrDebugHudStereo_QuadWithCrosshair = 2, ///< Renders Quad+crosshair in world for Stereo Debugging
+ ovrDebugHudStereo_CrosshairAtInfinity = 3, ///< Renders screen-space crosshair at infinity for Stereo Debugging
+ ovrDebugHudStereo_Count, ///< \internal Count of enumerated elements
+
+ ovrDebugHudStereo_EnumSize = 0x7fffffff ///< \internal Force type int32_t
+} ovrDebugHudStereoMode;
+
+
+#if !defined(OVR_EXPORTING_CAPI)
+
+// -----------------------------------------------------------------------------------
+/// @name Property Access
+///
+/// These functions read and write OVR properties. Supported properties
+/// are defined in OVR_CAPI_Keys.h
+///
+//@{
+
+/// Reads a boolean property.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] propertyName The name of the property, which needs to be valid for only the call.
+/// \param[in] defaultVal specifes the value to return if the property couldn't be read.
+/// \return Returns the property interpreted as a boolean value. Returns defaultVal if
+/// the property doesn't exist.
+OVR_PUBLIC_FUNCTION(ovrBool) ovr_GetBool(ovrSession session, const char* propertyName, ovrBool defaultVal);
+
+/// Writes or creates a boolean property.
+/// If the property wasn't previously a boolean property, it is changed to a boolean property.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] propertyName The name of the property, which needs to be valid only for the call.
+/// \param[in] value The value to write.
+/// \return Returns true if successful, otherwise false. A false result should only occur if the property
+/// name is empty or if the property is read-only.
+OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetBool(ovrSession session, const char* propertyName, ovrBool value);
+
+
+/// Reads an integer property.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] propertyName The name of the property, which needs to be valid only for the call.
+/// \param[in] defaultVal Specifes the value to return if the property couldn't be read.
+/// \return Returns the property interpreted as an integer value. Returns defaultVal if
+/// the property doesn't exist.
+OVR_PUBLIC_FUNCTION(int) ovr_GetInt(ovrSession session, const char* propertyName, int defaultVal);
+
+/// Writes or creates an integer property.
+///
+/// If the property wasn't previously a boolean property, it is changed to an integer property.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] propertyName The name of the property, which needs to be valid only for the call.
+/// \param[in] value The value to write.
+/// \return Returns true if successful, otherwise false. A false result should only occur if the property
+/// name is empty or if the property is read-only.
+OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetInt(ovrSession session, const char* propertyName, int value);
+
+
+/// Reads a float property.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] propertyName The name of the property, which needs to be valid only for the call.
+/// \param[in] defaultVal specifes the value to return if the property couldn't be read.
+/// \return Returns the property interpreted as an float value. Returns defaultVal if
+/// the property doesn't exist.
+OVR_PUBLIC_FUNCTION(float) ovr_GetFloat(ovrSession session, const char* propertyName, float defaultVal);
+
+/// Writes or creates a float property.
+/// If the property wasn't previously a float property, it's changed to a float property.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] propertyName The name of the property, which needs to be valid only for the call.
+/// \param[in] value The value to write.
+/// \return Returns true if successful, otherwise false. A false result should only occur if the property
+/// name is empty or if the property is read-only.
+OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetFloat(ovrSession session, const char* propertyName, float value);
+
+
+/// Reads a float array property.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] propertyName The name of the property, which needs to be valid only for the call.
+/// \param[in] values An array of float to write to.
+/// \param[in] valuesCapacity Specifies the maximum number of elements to write to the values array.
+/// \return Returns the number of elements read, or 0 if property doesn't exist or is empty.
+OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetFloatArray(ovrSession session, const char* propertyName,
+ float values[], unsigned int valuesCapacity);
+
+/// Writes or creates a float array property.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] propertyName The name of the property, which needs to be valid only for the call.
+/// \param[in] values An array of float to write from.
+/// \param[in] valuesSize Specifies the number of elements to write.
+/// \return Returns true if successful, otherwise false. A false result should only occur if the property
+/// name is empty or if the property is read-only.
+OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetFloatArray(ovrSession session, const char* propertyName,
+ const float values[], unsigned int valuesSize);
+
+
+/// Reads a string property.
+/// Strings are UTF8-encoded and null-terminated.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] propertyName The name of the property, which needs to be valid only for the call.
+/// \param[in] defaultVal Specifes the value to return if the property couldn't be read.
+/// \return Returns the string property if it exists. Otherwise returns defaultVal, which can be specified as NULL.
+/// The return memory is guaranteed to be valid until next call to ovr_GetString or
+/// until the session is destroyed, whichever occurs first.
+OVR_PUBLIC_FUNCTION(const char*) ovr_GetString(ovrSession session, const char* propertyName,
+ const char* defaultVal);
+
+/// Writes or creates a string property.
+/// Strings are UTF8-encoded and null-terminated.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] propertyName The name of the property, which needs to be valid only for the call.
+/// \param[in] value The string property, which only needs to be valid for the duration of the call.
+/// \return Returns true if successful, otherwise false. A false result should only occur if the property
+/// name is empty or if the property is read-only.
+OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetString(ovrSession session, const char* propertyName,
+ const char* value);
+
+///@}
+
+#endif // !defined(OVR_EXPORTING_CAPI)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+
+#if defined(_MSC_VER)
+ #pragma warning(pop)
+#endif
+
+/// @cond DoxygenIgnore
+//-----------------------------------------------------------------------------
+// ***** Compiler packing validation
+//
+// These checks ensure that the compiler settings being used will be compatible
+// with with pre-built dynamic library provided with the runtime.
+
+OVR_STATIC_ASSERT(sizeof(ovrBool) == 1, "ovrBool size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrVector2i) == 4 * 2, "ovrVector2i size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrSizei) == 4 * 2, "ovrSizei size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrRecti) == sizeof(ovrVector2i) + sizeof(ovrSizei), "ovrRecti size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrQuatf) == 4 * 4, "ovrQuatf size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrVector2f) == 4 * 2, "ovrVector2f size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrVector3f) == 4 * 3, "ovrVector3f size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrMatrix4f) == 4 * 16, "ovrMatrix4f size mismatch");
+
+OVR_STATIC_ASSERT(sizeof(ovrPosef) == (7 * 4), "ovrPosef size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrPoseStatef) == (22 * 4), "ovrPoseStatef size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrFovPort) == (4 * 4), "ovrFovPort size mismatch");
+
+OVR_STATIC_ASSERT(sizeof(ovrHmdCaps) == 4, "ovrHmdCaps size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrTrackingCaps) == 4, "ovrTrackingCaps size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrEyeType) == 4, "ovrEyeType size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrHmdType) == 4, "ovrHmdType size mismatch");
+
+OVR_STATIC_ASSERT(sizeof(ovrTrackerDesc) == 4 + 4 + 4 + 4, "ovrTrackerDesc size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrTrackerPose) == 4 + 4 + sizeof(ovrPosef) + sizeof(ovrPosef), "ovrTrackerPose size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrTrackingState) == sizeof(ovrPoseStatef) + 4 + 4 + (sizeof(ovrPoseStatef) * 2) + (sizeof(unsigned int) * 2) + sizeof(ovrPosef) + 4, "ovrTrackingState size mismatch");
+
+
+//OVR_STATIC_ASSERT(sizeof(ovrTextureHeader) == sizeof(ovrRenderAPIType) + sizeof(ovrSizei),
+// "ovrTextureHeader size mismatch");
+//OVR_STATIC_ASSERT(sizeof(ovrTexture) == sizeof(ovrTextureHeader) OVR_ON64(+4) + sizeof(uintptr_t) * 8,
+// "ovrTexture size mismatch");
+//
+OVR_STATIC_ASSERT(sizeof(ovrStatusBits) == 4, "ovrStatusBits size mismatch");
+
+OVR_STATIC_ASSERT(sizeof(ovrSessionStatus) == 6, "ovrSessionStatus size mismatch");
+
+OVR_STATIC_ASSERT(sizeof(ovrEyeRenderDesc) == sizeof(ovrEyeType) + sizeof(ovrFovPort) + sizeof(ovrRecti) +
+ sizeof(ovrVector2f) + sizeof(ovrVector3f),
+ "ovrEyeRenderDesc size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrTimewarpProjectionDesc) == 4 * 3, "ovrTimewarpProjectionDesc size mismatch");
+
+OVR_STATIC_ASSERT(sizeof(ovrInitFlags) == 4, "ovrInitFlags size mismatch");
+OVR_STATIC_ASSERT(sizeof(ovrLogLevel) == 4, "ovrLogLevel size mismatch");
+
+OVR_STATIC_ASSERT(sizeof(ovrInitParams) == 4 + 4 + sizeof(ovrLogCallback) + sizeof(uintptr_t) + 4 + 4,
+ "ovrInitParams size mismatch");
+
+OVR_STATIC_ASSERT(sizeof(ovrHmdDesc) ==
+ + sizeof(ovrHmdType) // Type
+ OVR_ON64(+ 4) // pad0
+ + 64 // ProductName
+ + 64 // Manufacturer
+ + 2 // VendorId
+ + 2 // ProductId
+ + 24 // SerialNumber
+ + 2 // FirmwareMajor
+ + 2 // FirmwareMinor
+ + 4 * 4 // AvailableHmdCaps - DefaultTrackingCaps
+ + sizeof(ovrFovPort) * 2 // DefaultEyeFov
+ + sizeof(ovrFovPort) * 2 // MaxEyeFov
+ + sizeof(ovrSizei) // Resolution
+ + 4 // DisplayRefreshRate
+ OVR_ON64(+ 4) // pad1
+ , "ovrHmdDesc size mismatch");
+
+
+// -----------------------------------------------------------------------------------
+// ***** Backward compatibility #includes
+//
+// This is at the bottom of this file because the following is dependent on the
+// declarations above.
+
+#if !defined(OVR_CAPI_NO_UTILS)
+ #include "Extras/OVR_CAPI_Util.h"
+#endif
+
+/// @endcond
+
+#endif // OVR_CAPI_h
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h
new file mode 100644
index 00000000..dc61e19e
--- /dev/null
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h
@@ -0,0 +1,84 @@
+/********************************************************************************//**
+\file OVR_CAPI_Audio.h
+\brief CAPI audio functions.
+\copyright Copyright 2015 Oculus VR, LLC. All Rights reserved.
+************************************************************************************/
+
+
+#ifndef OVR_CAPI_Audio_h
+#define OVR_CAPI_Audio_h
+
+#ifdef _WIN32
+// Prevents <Windows.h> from defining min() and max() macro symbols.
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <windows.h>
+#include "OVR_CAPI.h"
+#define OVR_AUDIO_MAX_DEVICE_STR_SIZE 128
+
+#if !defined(OVR_EXPORTING_CAPI)
+
+/// Gets the ID of the preferred VR audio output device.
+///
+/// \param[out] deviceOutId The ID of the user's preferred VR audio device to use, which will be valid upon a successful return value, else it will be WAVE_MAPPER.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceOutWaveId(UINT* deviceOutId);
+
+/// Gets the ID of the preferred VR audio input device.
+///
+/// \param[out] deviceInId The ID of the user's preferred VR audio device to use, which will be valid upon a successful return value, else it will be WAVE_MAPPER.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInWaveId(UINT* deviceInId);
+
+
+/// Gets the GUID of the preferred VR audio device as a string.
+///
+/// \param[out] deviceOutStrBuffer A buffer where the GUID string for the device will copied to.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceOutGuidStr(WCHAR deviceOutStrBuffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]);
+
+
+/// Gets the GUID of the preferred VR audio device.
+///
+/// \param[out] deviceOutGuid The GUID of the user's preferred VR audio device to use, which will be valid upon a successful return value, else it will be NULL.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceOutGuid(GUID* deviceOutGuid);
+
+
+/// Gets the GUID of the preferred VR microphone device as a string.
+///
+/// \param[out] deviceInStrBuffer A buffer where the GUID string for the device will copied to.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInGuidStr(WCHAR deviceInStrBuffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]);
+
+
+/// Gets the GUID of the preferred VR microphone device.
+///
+/// \param[out] deviceInGuid The GUID of the user's preferred VR audio device to use, which will be valid upon a successful return value, else it will be NULL.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInGuid(GUID* deviceInGuid);
+
+#endif // !defined(OVR_EXPORTING_CAPI)
+
+#endif //OVR_OS_MS
+
+#endif // OVR_CAPI_Audio_h
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h
new file mode 100644
index 00000000..374dab84
--- /dev/null
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h
@@ -0,0 +1,158 @@
+/********************************************************************************//**
+\file OVR_CAPI_D3D.h
+\brief D3D specific structures used by the CAPI interface.
+\copyright Copyright 2014-2016 Oculus VR, LLC All Rights reserved.
+************************************************************************************/
+
+#ifndef OVR_CAPI_D3D_h
+#define OVR_CAPI_D3D_h
+
+#include "OVR_CAPI.h"
+#include "OVR_Version.h"
+
+
+#if defined (_WIN32)
+#include <Unknwn.h>
+
+#if !defined(OVR_EXPORTING_CAPI)
+
+//-----------------------------------------------------------------------------------
+// ***** Direct3D Specific
+
+/// Create Texture Swap Chain suitable for use with Direct3D 11 and 12.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] d3dPtr Specifies the application's D3D11Device to create resources with or the D3D12CommandQueue
+/// which must be the same one the application renders to the eye textures with.
+/// \param[in] desc Specifies requested texture properties. See notes for more info about texture format.
+/// \param[in] bindFlags Specifies what ovrTextureBindFlags the application requires for this texture chain.
+/// \param[out] out_TextureSwapChain Returns the created ovrTextureSwapChain, which will be valid upon a successful return value, else it will be NULL.
+/// This texture chain must be eventually destroyed via ovr_DestroyTextureSwapChain before destroying the session with ovr_Destroy.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+/// \note The texture format provided in \a desc should be thought of as the format the distortion-compositor will use for the
+/// ShaderResourceView when reading the contents of the texture. To that end, it is highly recommended that the application
+/// requests texture swapchain formats that are in sRGB-space (e.g. OVR_FORMAT_R8G8B8A8_UNORM_SRGB) as the compositor
+/// does sRGB-correct rendering. As such, the compositor relies on the GPU's hardware sampler to do the sRGB-to-linear
+/// conversion. If the application still prefers to render to a linear format (e.g. OVR_FORMAT_R8G8B8A8_UNORM) while handling the
+/// linear-to-gamma conversion via HLSL code, then the application must still request the corresponding sRGB format and also use
+/// the \a ovrTextureMisc_DX_Typeless flag in the ovrTextureSwapChainDesc's Flag field. This will allow the application to create
+/// a RenderTargetView that is the desired linear format while the compositor continues to treat it as sRGB. Failure to do so
+/// will cause the compositor to apply unexpected gamma conversions leading to gamma-curve artifacts. The \a ovrTextureMisc_DX_Typeless
+/// flag for depth buffer formats (e.g. OVR_FORMAT_D32_FLOAT) is ignored as they are always converted to be typeless.
+///
+/// \see ovr_GetTextureSwapChainLength
+/// \see ovr_GetTextureSwapChainCurrentIndex
+/// \see ovr_GetTextureSwapChainDesc
+/// \see ovr_GetTextureSwapChainBufferDX
+/// \see ovr_DestroyTextureSwapChain
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_CreateTextureSwapChainDX(ovrSession session,
+ IUnknown* d3dPtr,
+ const ovrTextureSwapChainDesc* desc,
+ ovrTextureSwapChain* out_TextureSwapChain);
+
+
+/// Get a specific buffer within the chain as any compatible COM interface (similar to QueryInterface)
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] chain Specifies an ovrTextureSwapChain previously returned by ovr_CreateTextureSwapChainDX
+/// \param[in] index Specifies the index within the chain to retrieve. Must be between 0 and length (see ovr_GetTextureSwapChainLength),
+/// or may pass -1 to get the buffer at the CurrentIndex location. (Saving a call to GetTextureSwapChainCurrentIndex)
+/// \param[in] iid Specifies the interface ID of the interface pointer to query the buffer for.
+/// \param[out] out_Buffer Returns the COM interface pointer retrieved.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+/// <b>Example code</b>
+/// \code{.cpp}
+/// ovr_GetTextureSwapChainBufferDX(session, chain, 0, IID_ID3D11Texture2D, &d3d11Texture);
+/// ovr_GetTextureSwapChainBufferDX(session, chain, 1, IID_PPV_ARGS(&dxgiResource));
+/// \endcode
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainBufferDX(ovrSession session,
+ ovrTextureSwapChain chain,
+ int index,
+ IID iid,
+ void** out_Buffer);
+
+
+/// Create Mirror Texture which is auto-refreshed to mirror Rift contents produced by this application.
+///
+/// A second call to ovr_CreateMirrorTextureDX for a given ovrSession before destroying the first one
+/// is not supported and will result in an error return.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] d3dPtr Specifies the application's D3D11Device to create resources with or the D3D12CommandQueue
+/// which must be the same one the application renders to the textures with.
+/// \param[in] desc Specifies requested texture properties. See notes for more info about texture format.
+/// \param[out] out_MirrorTexture Returns the created ovrMirrorTexture, which will be valid upon a successful return value, else it will be NULL.
+/// This texture must be eventually destroyed via ovr_DestroyMirrorTexture before destroying the session with ovr_Destroy.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+/// \note The texture format provided in \a desc should be thought of as the format the compositor will use for the RenderTargetView when
+/// writing into mirror texture. To that end, it is highly recommended that the application requests a mirror texture format that is
+/// in sRGB-space (e.g. OVR_FORMAT_R8G8B8A8_UNORM_SRGB) as the compositor does sRGB-correct rendering. If however the application wants
+/// to still read the mirror texture as a linear format (e.g. OVR_FORMAT_R8G8B8A8_UNORM) and handle the sRGB-to-linear conversion in
+/// HLSL code, then it is recommended the application still requests an sRGB format and also use the \a ovrTextureMisc_DX_Typeless flag in the
+/// ovrMirrorTextureDesc's Flags field. This will allow the application to bind a ShaderResourceView that is a linear format while the
+/// compositor continues to treat is as sRGB. Failure to do so will cause the compositor to apply unexpected gamma conversions leading to
+/// gamma-curve artifacts.
+///
+///
+/// <b>Example code</b>
+/// \code{.cpp}
+/// ovrMirrorTexture mirrorTexture = nullptr;
+/// ovrMirrorTextureDesc mirrorDesc = {};
+/// mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
+/// mirrorDesc.Width = mirrorWindowWidth;
+/// mirrorDesc.Height = mirrorWindowHeight;
+/// ovrResult result = ovr_CreateMirrorTextureDX(session, d3d11Device, &mirrorDesc, &mirrorTexture);
+/// [...]
+/// // Destroy the texture when done with it.
+/// ovr_DestroyMirrorTexture(session, mirrorTexture);
+/// mirrorTexture = nullptr;
+/// \endcode
+///
+/// \see ovr_GetMirrorTextureBufferDX
+/// \see ovr_DestroyMirrorTexture
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_CreateMirrorTextureDX(ovrSession session,
+ IUnknown* d3dPtr,
+ const ovrMirrorTextureDesc* desc,
+ ovrMirrorTexture* out_MirrorTexture);
+
+/// Get a the underlying buffer as any compatible COM interface (similar to QueryInterface)
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] mirrorTexture Specifies an ovrMirrorTexture previously returned by ovr_CreateMirrorTextureDX
+/// \param[in] iid Specifies the interface ID of the interface pointer to query the buffer for.
+/// \param[out] out_Buffer Returns the COM interface pointer retrieved.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+/// <b>Example code</b>
+/// \code{.cpp}
+/// ID3D11Texture2D* d3d11Texture = nullptr;
+/// ovr_GetMirrorTextureBufferDX(session, mirrorTexture, IID_PPV_ARGS(&d3d11Texture));
+/// d3d11DeviceContext->CopyResource(d3d11TextureBackBuffer, d3d11Texture);
+/// d3d11Texture->Release();
+/// dxgiSwapChain->Present(0, 0);
+/// \endcode
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetMirrorTextureBufferDX(ovrSession session,
+ ovrMirrorTexture mirrorTexture,
+ IID iid,
+ void** out_Buffer);
+
+#endif // !defined(OVR_EXPORTING_CAPI)
+
+#endif // _WIN32
+
+#endif // OVR_CAPI_D3D_h
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h
new file mode 100644
index 00000000..1c073f46
--- /dev/null
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h
@@ -0,0 +1,102 @@
+/********************************************************************************//**
+\file OVR_CAPI_GL.h
+\brief OpenGL-specific structures used by the CAPI interface.
+\copyright Copyright 2015 Oculus VR, LLC. All Rights reserved.
+************************************************************************************/
+
+#ifndef OVR_CAPI_GL_h
+#define OVR_CAPI_GL_h
+
+#include "OVR_CAPI.h"
+
+#if !defined(OVR_EXPORTING_CAPI)
+
+/// Creates a TextureSwapChain suitable for use with OpenGL.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] desc Specifies the requested texture properties. See notes for more info about texture format.
+/// \param[out] out_TextureSwapChain Returns the created ovrTextureSwapChain, which will be valid upon
+/// a successful return value, else it will be NULL. This texture swap chain must be eventually
+/// destroyed via ovr_DestroyTextureSwapChain before destroying the session with ovr_Destroy.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+/// \note The \a format provided should be thought of as the format the distortion compositor will use when reading
+/// the contents of the texture. To that end, it is highly recommended that the application requests texture swap chain
+/// formats that are in sRGB-space (e.g. OVR_FORMAT_R8G8B8A8_UNORM_SRGB) as the distortion compositor does sRGB-correct
+/// rendering. Furthermore, the app should then make sure "glEnable(GL_FRAMEBUFFER_SRGB);" is called before rendering
+/// into these textures. Even though it is not recommended, if the application would like to treat the texture as a linear
+/// format and do linear-to-gamma conversion in GLSL, then the application can avoid calling "glEnable(GL_FRAMEBUFFER_SRGB);",
+/// but should still pass in an sRGB variant for the \a format. Failure to do so will cause the distortion compositor
+/// to apply incorrect gamma conversions leading to gamma-curve artifacts.
+///
+/// \see ovr_GetTextureSwapChainLength
+/// \see ovr_GetTextureSwapChainCurrentIndex
+/// \see ovr_GetTextureSwapChainDesc
+/// \see ovr_GetTextureSwapChainBufferGL
+/// \see ovr_DestroyTextureSwapChain
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_CreateTextureSwapChainGL(ovrSession session,
+ const ovrTextureSwapChainDesc* desc,
+ ovrTextureSwapChain* out_TextureSwapChain);
+
+/// Get a specific buffer within the chain as a GL texture name
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] chain Specifies an ovrTextureSwapChain previously returned by ovr_CreateTextureSwapChainGL
+/// \param[in] index Specifies the index within the chain to retrieve. Must be between 0 and length (see ovr_GetTextureSwapChainLength)
+/// or may pass -1 to get the buffer at the CurrentIndex location. (Saving a call to GetTextureSwapChainCurrentIndex)
+/// \param[out] out_TexId Returns the GL texture object name associated with the specific index requested
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainBufferGL(ovrSession session,
+ ovrTextureSwapChain chain,
+ int index,
+ unsigned int* out_TexId);
+
+
+/// Creates a Mirror Texture which is auto-refreshed to mirror Rift contents produced by this application.
+///
+/// A second call to ovr_CreateMirrorTextureGL for a given ovrSession before destroying the first one
+/// is not supported and will result in an error return.
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] desc Specifies the requested mirror texture description.
+/// \param[out] out_MirrorTexture Specifies the created ovrMirrorTexture, which will be valid upon a successful return value, else it will be NULL.
+/// This texture must be eventually destroyed via ovr_DestroyMirrorTexture before destroying the session with ovr_Destroy.
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+/// \note The \a format provided should be thought of as the format the distortion compositor will use when writing into the mirror
+/// texture. It is highly recommended that mirror textures are requested as sRGB formats because the distortion compositor
+/// does sRGB-correct rendering. If the application requests a non-sRGB format (e.g. R8G8B8A8_UNORM) as the mirror texture,
+/// then the application might have to apply a manual linear-to-gamma conversion when reading from the mirror texture.
+/// Failure to do so can result in incorrect gamma conversions leading to gamma-curve artifacts and color banding.
+///
+/// \see ovr_GetMirrorTextureBufferGL
+/// \see ovr_DestroyMirrorTexture
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_CreateMirrorTextureGL(ovrSession session,
+ const ovrMirrorTextureDesc* desc,
+ ovrMirrorTexture* out_MirrorTexture);
+
+/// Get a the underlying buffer as a GL texture name
+///
+/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
+/// \param[in] mirrorTexture Specifies an ovrMirrorTexture previously returned by ovr_CreateMirrorTextureGL
+/// \param[out] out_TexId Specifies the GL texture object name associated with the mirror texture
+///
+/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
+/// ovr_GetLastErrorInfo to get more information.
+///
+OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetMirrorTextureBufferGL(ovrSession session,
+ ovrMirrorTexture mirrorTexture,
+ unsigned int* out_TexId);
+
+#endif // !defined(OVR_EXPORTING_CAPI)
+
+#endif // OVR_CAPI_GL_h
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Keys.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Keys.h
new file mode 100644
index 00000000..e3e9d689
--- /dev/null
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Keys.h
@@ -0,0 +1,53 @@
+/********************************************************************************//**
+\file OVR_CAPI.h
+\brief Keys for CAPI proprty function calls
+\copyright Copyright 2015 Oculus VR, LLC All Rights reserved.
+************************************************************************************/
+
+#ifndef OVR_CAPI_Keys_h
+#define OVR_CAPI_Keys_h
+
+#include "OVR_Version.h"
+
+
+
+#define OVR_KEY_USER "User" // string
+
+#define OVR_KEY_NAME "Name" // string
+
+#define OVR_KEY_GENDER "Gender" // string "Male", "Female", or "Unknown"
+#define OVR_DEFAULT_GENDER "Unknown"
+
+#define OVR_KEY_PLAYER_HEIGHT "PlayerHeight" // float meters
+#define OVR_DEFAULT_PLAYER_HEIGHT 1.778f
+
+#define OVR_KEY_EYE_HEIGHT "EyeHeight" // float meters
+#define OVR_DEFAULT_EYE_HEIGHT 1.675f
+
+#define OVR_KEY_NECK_TO_EYE_DISTANCE "NeckEyeDistance" // float[2] meters
+#define OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL 0.0805f
+#define OVR_DEFAULT_NECK_TO_EYE_VERTICAL 0.075f
+
+
+#define OVR_KEY_EYE_TO_NOSE_DISTANCE "EyeToNoseDist" // float[2] meters
+
+
+
+
+
+#define OVR_PERF_HUD_MODE "PerfHudMode" // int, allowed values are defined in enum ovrPerfHudMode
+
+#define OVR_LAYER_HUD_MODE "LayerHudMode" // int, allowed values are defined in enum ovrLayerHudMode
+#define OVR_LAYER_HUD_CURRENT_LAYER "LayerHudCurrentLayer" // int, The layer to show
+#define OVR_LAYER_HUD_SHOW_ALL_LAYERS "LayerHudShowAll" // bool, Hide other layers when the hud is enabled
+
+#define OVR_DEBUG_HUD_STEREO_MODE "DebugHudStereoMode" // int, allowed values are defined in enum ovrDebugHudStereoMode
+#define OVR_DEBUG_HUD_STEREO_GUIDE_INFO_ENABLE "DebugHudStereoGuideInfoEnable" // bool
+#define OVR_DEBUG_HUD_STEREO_GUIDE_SIZE "DebugHudStereoGuideSize2f" // float[2]
+#define OVR_DEBUG_HUD_STEREO_GUIDE_POSITION "DebugHudStereoGuidePosition3f" // float[3]
+#define OVR_DEBUG_HUD_STEREO_GUIDE_YAWPITCHROLL "DebugHudStereoGuideYawPitchRoll3f" // float[3]
+#define OVR_DEBUG_HUD_STEREO_GUIDE_COLOR "DebugHudStereoGuideColor4f" // float[4]
+
+
+
+#endif // OVR_CAPI_Keys_h
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h b/src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h
new file mode 100644
index 00000000..a8b810ea
--- /dev/null
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h
@@ -0,0 +1,156 @@
+/********************************************************************************//**
+\file OVR_ErrorCode.h
+\brief This header provides LibOVR error code declarations.
+\copyright Copyright 2015-2016 Oculus VR, LLC All Rights reserved.
+*************************************************************************************/
+
+#ifndef OVR_ErrorCode_h
+#define OVR_ErrorCode_h
+
+
+#include "OVR_Version.h"
+#include <stdint.h>
+
+
+
+
+#ifndef OVR_RESULT_DEFINED
+#define OVR_RESULT_DEFINED ///< Allows ovrResult to be independently defined.
+/// API call results are represented at the highest level by a single ovrResult.
+typedef int32_t ovrResult;
+#endif
+
+
+/// \brief Indicates if an ovrResult indicates success.
+///
+/// Some functions return additional successful values other than ovrSucces and
+/// require usage of this macro to indicate successs.
+///
+#if !defined(OVR_SUCCESS)
+ #define OVR_SUCCESS(result) (result >= 0)
+#endif
+
+
+/// \brief Indicates if an ovrResult indicates an unqualified success.
+///
+/// This is useful for indicating that the code intentionally wants to
+/// check for result == ovrSuccess as opposed to OVR_SUCCESS(), which
+/// checks for result >= ovrSuccess.
+///
+#if !defined(OVR_UNQUALIFIED_SUCCESS)
+ #define OVR_UNQUALIFIED_SUCCESS(result) (result == ovrSuccess)
+#endif
+
+
+/// \brief Indicates if an ovrResult indicates failure.
+///
+#if !defined(OVR_FAILURE)
+ #define OVR_FAILURE(result) (!OVR_SUCCESS(result))
+#endif
+
+
+// Success is a value greater or equal to 0, while all error types are negative values.
+#ifndef OVR_SUCCESS_DEFINED
+#define OVR_SUCCESS_DEFINED ///< Allows ovrResult to be independently defined.
+typedef enum ovrSuccessType_
+{
+ /// This is a general success result. Use OVR_SUCCESS to test for success.
+ ovrSuccess = 0,
+} ovrSuccessType;
+#endif
+
+// Public success types
+// Success is a value greater or equal to 0, while all error types are negative values.
+typedef enum ovrSuccessTypes_
+{
+ /// Returned from a call to SubmitFrame. The call succeeded, but what the app
+ /// rendered will not be visible on the HMD. Ideally the app should continue
+ /// calling SubmitFrame, but not do any rendering. When the result becomes
+ /// ovrSuccess, rendering should continue as usual.
+ ovrSuccess_NotVisible = 1000,
+
+} ovrSuccessTypes;
+
+// Public error types
+typedef enum ovrErrorType_
+{
+ /* General errors */
+ ovrError_MemoryAllocationFailure = -1000, ///< Failure to allocate memory.
+ ovrError_InvalidSession = -1002, ///< Invalid ovrSession parameter provided.
+ ovrError_Timeout = -1003, ///< The operation timed out.
+ ovrError_NotInitialized = -1004, ///< The system or component has not been initialized.
+ ovrError_InvalidParameter = -1005, ///< Invalid parameter provided. See error info or log for details.
+ ovrError_ServiceError = -1006, ///< Generic service error. See error info or log for details.
+ ovrError_NoHmd = -1007, ///< The given HMD doesn't exist.
+ ovrError_Unsupported = -1009, ///< Function call is not supported on this hardware/software
+ ovrError_DeviceUnavailable = -1010, ///< Specified device type isn't available.
+ ovrError_InvalidHeadsetOrientation = -1011, ///< The headset was in an invalid orientation for the requested operation (e.g. vertically oriented during ovr_RecenterPose).
+ ovrError_ClientSkippedDestroy = -1012, ///< The client failed to call ovr_Destroy on an active session before calling ovr_Shutdown. Or the client crashed.
+ ovrError_ClientSkippedShutdown = -1013, ///< The client failed to call ovr_Shutdown or the client crashed.
+ ovrError_ServiceDeadlockDetected = -1014, ///< The service watchdog discovered a deadlock.
+ ovrError_InvalidOperation = -1015, ///< Function call is invalid for object's current state
+
+ /* Audio error range, reserved for Audio errors. */
+ ovrError_AudioDeviceNotFound = -2001, ///< Failure to find the specified audio device.
+ ovrError_AudioComError = -2002, ///< Generic COM error.
+
+ /* Initialization errors. */
+ ovrError_Initialize = -3000, ///< Generic initialization error.
+ ovrError_LibLoad = -3001, ///< Couldn't load LibOVRRT.
+ ovrError_LibVersion = -3002, ///< LibOVRRT version incompatibility.
+ ovrError_ServiceConnection = -3003, ///< Couldn't connect to the OVR Service.
+ ovrError_ServiceVersion = -3004, ///< OVR Service version incompatibility.
+ ovrError_IncompatibleOS = -3005, ///< The operating system version is incompatible.
+ ovrError_DisplayInit = -3006, ///< Unable to initialize the HMD display.
+ ovrError_ServerStart = -3007, ///< Unable to start the server. Is it already running?
+ ovrError_Reinitialization = -3008, ///< Attempting to re-initialize with a different version.
+ ovrError_MismatchedAdapters = -3009, ///< Chosen rendering adapters between client and service do not match
+ ovrError_LeakingResources = -3010, ///< Calling application has leaked resources
+ ovrError_ClientVersion = -3011, ///< Client version too old to connect to service
+ ovrError_OutOfDateOS = -3012, ///< The operating system is out of date.
+ ovrError_OutOfDateGfxDriver = -3013, ///< The graphics driver is out of date.
+ ovrError_IncompatibleGPU = -3014, ///< The graphics hardware is not supported
+ ovrError_NoValidVRDisplaySystem = -3015, ///< No valid VR display system found.
+ ovrError_Obsolete = -3016, ///< Feature or API is obsolete and no longer supported.
+ ovrError_DisabledOrDefaultAdapter = -3017, ///< No supported VR display system found, but disabled or driverless adapter found.
+ ovrError_HybridGraphicsNotSupported = -3018, ///< The system is using hybrid graphics (Optimus, etc...), which is not support.
+ ovrError_DisplayManagerInit = -3019, ///< Initialization of the DisplayManager failed.
+ ovrError_TrackerDriverInit = -3020, ///< Failed to get the interface for an attached tracker
+ ovrError_LibSignCheck = -3021, ///< LibOVRRT signature check failure.
+ ovrError_LibPath = -3022, ///< LibOVRRT path failure.
+ ovrError_LibSymbols = -3023, ///< LibOVRRT symbol resolution failure.
+
+ /* Rendering errors */
+ ovrError_DisplayLost = -6000, ///< In the event of a system-wide graphics reset or cable unplug this is returned to the app.
+ ovrError_TextureSwapChainFull = -6001, ///< ovr_CommitTextureSwapChain was called too many times on a texture swapchain without calling submit to use the chain.
+ ovrError_TextureSwapChainInvalid = -6002, ///< The ovrTextureSwapChain is in an incomplete or inconsistent state. Ensure ovr_CommitTextureSwapChain was called at least once first.
+ ovrError_GraphicsDeviceReset = -6003, ///< Graphics device has been reset (TDR, etc...)
+ ovrError_DisplayRemoved = -6004, ///< HMD removed from the display adapter
+ ovrError_ContentProtectionNotAvailable = -6005,///<Content protection is not available for the display
+ ovrError_ApplicationInvisible = -6006, ///< Application declared itself as an invisible type and is not allowed to submit frames.
+ ovrError_Disallowed = -6007, ///< The given request is disallowed under the current conditions.
+ ovrError_DisplayPluggedIncorrectly = -6008, ///< Display portion of HMD is plugged into an incompatible port (ex: IGP)
+
+ /* Fatal errors */
+ ovrError_RuntimeException = -7000, ///< A runtime exception occurred. The application is required to shutdown LibOVR and re-initialize it before this error state will be cleared.
+
+ /* Calibration errors */
+ ovrError_NoCalibration = -9000, ///< Result of a missing calibration block
+ ovrError_OldVersion = -9001, ///< Result of an old calibration block
+ ovrError_MisformattedBlock = -9002, ///< Result of a bad calibration block due to lengths
+
+
+} ovrErrorType;
+
+
+
+/// Provides information about the last error.
+/// \see ovr_GetLastErrorInfo
+typedef struct ovrErrorInfo_
+{
+ ovrResult Result; ///< The result from the last API call that generated an error ovrResult.
+ char ErrorString[512]; ///< A UTF8-encoded null-terminated English string describing the problem. The format of this string is subject to change in future versions.
+} ovrErrorInfo;
+
+
+#endif /* OVR_ErrorCode_h */
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_Version.h b/src/external/OculusSDK/LibOVR/Include/OVR_Version.h
new file mode 100644
index 00000000..8d213df5
--- /dev/null
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_Version.h
@@ -0,0 +1,60 @@
+/********************************************************************************//**
+\file OVR_Version.h
+\brief This header provides LibOVR version identification.
+\copyright Copyright 2014-2016 Oculus VR, LLC All Rights reserved.
+*************************************************************************************/
+
+#ifndef OVR_Version_h
+#define OVR_Version_h
+
+
+
+/// Conventional string-ification macro.
+#if !defined(OVR_STRINGIZE)
+ #define OVR_STRINGIZEIMPL(x) #x
+ #define OVR_STRINGIZE(x) OVR_STRINGIZEIMPL(x)
+#endif
+
+
+// Master version numbers
+#define OVR_PRODUCT_VERSION 1 // Product version doesn't participate in semantic versioning.
+#define OVR_MAJOR_VERSION 1 // If you change these values then you need to also make sure to change LibOVR/Projects/Windows/LibOVR.props in parallel.
+#define OVR_MINOR_VERSION 7 //
+#define OVR_PATCH_VERSION 0
+#define OVR_BUILD_NUMBER 0
+
+// This is the ((product * 100) + major) version of the service that the DLL is compatible with.
+// When we backport changes to old versions of the DLL we update the old DLLs
+// to move this version number up to the latest version.
+// The DLL is responsible for checking that the service is the version it supports
+// and returning an appropriate error message if it has not been made compatible.
+#define OVR_DLL_COMPATIBLE_VERSION 101
+
+#define OVR_FEATURE_VERSION 0
+
+
+/// "Major.Minor.Patch"
+#if !defined(OVR_VERSION_STRING)
+ #define OVR_VERSION_STRING OVR_STRINGIZE(OVR_MAJOR_VERSION.OVR_MINOR_VERSION.OVR_PATCH_VERSION)
+#endif
+
+
+/// "Major.Minor.Patch.Build"
+#if !defined(OVR_DETAILED_VERSION_STRING)
+ #define OVR_DETAILED_VERSION_STRING OVR_STRINGIZE(OVR_MAJOR_VERSION.OVR_MINOR_VERSION.OVR_PATCH_VERSION.OVR_BUILD_NUMBER)
+#endif
+
+
+/// \brief file description for version info
+/// This appears in the user-visible file properties. It is intended to convey publicly
+/// available additional information such as feature builds.
+#if !defined(OVR_FILE_DESCRIPTION_STRING)
+ #if defined(_DEBUG)
+ #define OVR_FILE_DESCRIPTION_STRING "dev build debug"
+ #else
+ #define OVR_FILE_DESCRIPTION_STRING "dev build"
+ #endif
+#endif
+
+
+#endif // OVR_Version_h
diff --git a/src/external/OculusSDK/LibOVR/LibOVRRT32_1.dll b/src/external/OculusSDK/LibOVR/LibOVRRT32_1.dll
new file mode 100644
index 00000000..7a42d443
--- /dev/null
+++ b/src/external/OculusSDK/LibOVR/LibOVRRT32_1.dll
Binary files differ
diff --git a/src/external/dr_flac.h b/src/external/dr_flac.h
new file mode 100644
index 00000000..d2bebea5
--- /dev/null
+++ b/src/external/dr_flac.h
@@ -0,0 +1,4564 @@
+// FLAC audio decoder. Public domain. See "unlicense" statement at the end of this file.
+// dr_flac - v0.4c - 2016-12-26
+//
+// David Reid - mackron@gmail.com
+
+// USAGE
+//
+// dr_flac is a single-file library. To use it, do something like the following in one .c file.
+// #define DR_FLAC_IMPLEMENTATION
+// #include "dr_flac.h"
+//
+// You can then #include this file in other parts of the program as you would with any other header file. To decode audio data,
+// do something like the following:
+//
+// drflac* pFlac = drflac_open_file("MySong.flac");
+// if (pFlac == NULL) {
+// // Failed to open FLAC file
+// }
+//
+// int32_t* pSamples = malloc(pFlac->totalSampleCount * sizeof(int32_t));
+// uint64_t numberOfInterleavedSamplesActuallyRead = drflac_read_s32(pFlac, pFlac->totalSampleCount, pSamples);
+//
+// The drflac object represents the decoder. It is a transparent type so all the information you need, such as the number of
+// channels and the bits per sample, should be directly accessible - just make sure you don't change their values. Samples are
+// always output as interleaved signed 32-bit PCM. In the example above a native FLAC stream was opened, however dr_flac has
+// seamless support for Ogg encapsulated FLAC streams as well.
+//
+// You do not need to decode the entire stream in one go - you just specify how many samples you'd like at any given time and
+// the decoder will give you as many samples as it can, up to the amount requested. Later on when you need the next batch of
+// samples, just call it again. Example:
+//
+// while (drflac_read_s32(pFlac, chunkSize, pChunkSamples) > 0) {
+// do_something();
+// }
+//
+// You can seek to a specific sample with drflac_seek_to_sample(). The given sample is based on interleaving. So for example,
+// if you were to seek to the sample at index 0 in a stereo stream, you'll be seeking to the first sample of the left channel.
+// The sample at index 1 will be the first sample of the right channel. The sample at index 2 will be the second sample of the
+// left channel, etc.
+//
+//
+// If you just want to quickly decode an entire FLAC file in one go you can do something like this:
+//
+// unsigned int channels;
+// unsigned int sampleRate;
+// uint64_t totalSampleCount;
+// int32_t* pSampleData = drflac_open_and_decode_file("MySong.flac", &channels, &sampleRate, &totalSampleCount);
+// if (pSampleData == NULL) {
+// // Failed to open and decode FLAC file.
+// }
+//
+// ...
+//
+// drflac_free(pSampleData);
+//
+//
+// If you need access to metadata (album art, etc.), use drflac_open_with_metadata(), drflac_open_file_with_metdata() or
+// drflac_open_memory_with_metadata(). The rationale for keeping these APIs separate is that they're slightly slower than the
+// normal versions and also just a little bit harder to use.
+//
+// dr_flac reports metadata to the application through the use of a callback, and every metadata block is reported before
+// drflac_open_with_metdata() returns. See https://github.com/mackron/dr_libs_tests/blob/master/dr_flac/dr_flac_test_2.c for
+// an example on how to read metadata.
+//
+//
+//
+// OPTIONS
+// #define these options before including this file.
+//
+// #define DR_FLAC_NO_STDIO
+// Disable drflac_open_file().
+//
+// #define DR_FLAC_NO_OGG
+// Disables support for Ogg/FLAC streams.
+//
+// #define DR_FLAC_NO_WIN32_IO
+// In the Win32 build, dr_flac uses the Win32 IO APIs for drflac_open_file() by default. This setting will make it use the
+// standard FILE APIs instead. Ignored when DR_FLAC_NO_STDIO is #defined. (The rationale for this configuration is that
+// there's a bug in one compiler's Win32 implementation of the FILE APIs which is not present in the Win32 IO APIs.)
+//
+// #define DR_FLAC_BUFFER_SIZE <number>
+// Defines the size of the internal buffer to store data from onRead(). This buffer is used to reduce the number of calls
+// back to the client for more data. Larger values means more memory, but better performance. My tests show diminishing
+// returns after about 4KB (which is the default). Consider reducing this if you have a very efficient implementation of
+// onRead(), or increase it if it's very inefficient. Must be a multiple of 8.
+//
+//
+//
+// QUICK NOTES
+// - Based on my tests, the performance of the 32-bit build is at about parity with the reference implementation. The 64-bit build
+// is slightly faster.
+// - dr_flac does not currently do any CRC checks.
+// - dr_flac should work fine with valid native FLAC files, but for broadcast streams it won't work if the header and STREAMINFO
+// block is unavailable.
+// - Audio data is output as signed 32-bit PCM, regardless of the bits per sample the FLAC stream is encoded as.
+// - This has not been tested on big-endian architectures.
+// - Rice codes in unencoded binary form (see https://xiph.org/flac/format.html#rice_partition) has not been tested. If anybody
+// knows where I can find some test files for this, let me know.
+// - Perverse and erroneous files have not been tested. Again, if you know where I can get some test files let me know.
+// - dr_flac is not thread-safe, but it's APIs can be called from any thread so long as you do your own synchronization.
+
+#ifndef dr_flac_h
+#define dr_flac_h
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifndef DR_SIZED_TYPES_DEFINED
+#define DR_SIZED_TYPES_DEFINED
+#if defined(_MSC_VER) && _MSC_VER < 1600
+typedef signed char dr_int8;
+typedef unsigned char dr_uint8;
+typedef signed short dr_int16;
+typedef unsigned short dr_uint16;
+typedef signed int dr_int32;
+typedef unsigned int dr_uint32;
+typedef signed __int64 dr_int64;
+typedef unsigned __int64 dr_uint64;
+#else
+#include <stdint.h>
+typedef int8_t dr_int8;
+typedef uint8_t dr_uint8;
+typedef int16_t dr_int16;
+typedef uint16_t dr_uint16;
+typedef int32_t dr_int32;
+typedef uint32_t dr_uint32;
+typedef int64_t dr_int64;
+typedef uint64_t dr_uint64;
+#endif
+typedef dr_int8 dr_bool8;
+typedef dr_int32 dr_bool32;
+#define DR_TRUE 1
+#define DR_FALSE 0
+#endif
+
+// As data is read from the client it is placed into an internal buffer for fast access. This controls the
+// size of that buffer. Larger values means more speed, but also more memory. In my testing there is diminishing
+// returns after about 4KB, but you can fiddle with this to suit your own needs. Must be a multiple of 8.
+#ifndef DR_FLAC_BUFFER_SIZE
+#define DR_FLAC_BUFFER_SIZE 4096
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Check if we can enable 64-bit optimizations.
+#if defined(_WIN64)
+#define DRFLAC_64BIT
+#endif
+
+#if defined(__GNUC__)
+#if defined(__x86_64__) || defined(__ppc64__)
+#define DRFLAC_64BIT
+#endif
+#endif
+
+#ifdef DRFLAC_64BIT
+typedef uint64_t drflac_cache_t;
+#else
+typedef uint32_t drflac_cache_t;
+#endif
+
+// The various metadata block types.
+#define DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO 0
+#define DRFLAC_METADATA_BLOCK_TYPE_PADDING 1
+#define DRFLAC_METADATA_BLOCK_TYPE_APPLICATION 2
+#define DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE 3
+#define DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT 4
+#define DRFLAC_METADATA_BLOCK_TYPE_CUESHEET 5
+#define DRFLAC_METADATA_BLOCK_TYPE_PICTURE 6
+#define DRFLAC_METADATA_BLOCK_TYPE_INVALID 127
+
+// The various picture types specified in the PICTURE block.
+#define DRFLAC_PICTURE_TYPE_OTHER 0
+#define DRFLAC_PICTURE_TYPE_FILE_ICON 1
+#define DRFLAC_PICTURE_TYPE_OTHER_FILE_ICON 2
+#define DRFLAC_PICTURE_TYPE_COVER_FRONT 3
+#define DRFLAC_PICTURE_TYPE_COVER_BACK 4
+#define DRFLAC_PICTURE_TYPE_LEAFLET_PAGE 5
+#define DRFLAC_PICTURE_TYPE_MEDIA 6
+#define DRFLAC_PICTURE_TYPE_LEAD_ARTIST 7
+#define DRFLAC_PICTURE_TYPE_ARTIST 8
+#define DRFLAC_PICTURE_TYPE_CONDUCTOR 9
+#define DRFLAC_PICTURE_TYPE_BAND 10
+#define DRFLAC_PICTURE_TYPE_COMPOSER 11
+#define DRFLAC_PICTURE_TYPE_LYRICIST 12
+#define DRFLAC_PICTURE_TYPE_RECORDING_LOCATION 13
+#define DRFLAC_PICTURE_TYPE_DURING_RECORDING 14
+#define DRFLAC_PICTURE_TYPE_DURING_PERFORMANCE 15
+#define DRFLAC_PICTURE_TYPE_SCREEN_CAPTURE 16
+#define DRFLAC_PICTURE_TYPE_BRIGHT_COLORED_FISH 17
+#define DRFLAC_PICTURE_TYPE_ILLUSTRATION 18
+#define DRFLAC_PICTURE_TYPE_BAND_LOGOTYPE 19
+#define DRFLAC_PICTURE_TYPE_PUBLISHER_LOGOTYPE 20
+
+typedef enum
+{
+ drflac_container_native,
+ drflac_container_ogg
+} drflac_container;
+
+typedef enum
+{
+ drflac_seek_origin_start,
+ drflac_seek_origin_current
+} drflac_seek_origin;
+
+// Packing is important on this structure because we map this directly to the raw data within the SEEKTABLE metadata block.
+#pragma pack(2)
+typedef struct
+{
+ uint64_t firstSample;
+ uint64_t frameOffset; // The offset from the first byte of the header of the first frame.
+ uint16_t sampleCount;
+} drflac_seekpoint;
+#pragma pack()
+
+typedef struct
+{
+ uint16_t minBlockSize;
+ uint16_t maxBlockSize;
+ uint32_t minFrameSize;
+ uint32_t maxFrameSize;
+ uint32_t sampleRate;
+ uint8_t channels;
+ uint8_t bitsPerSample;
+ uint64_t totalSampleCount;
+ uint8_t md5[16];
+} drflac_streaminfo;
+
+typedef struct
+{
+ // The metadata type. Use this to know how to interpret the data below.
+ uint32_t type;
+
+ // A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to
+ // not modify the contents of this buffer. Use the structures below for more meaningful and structured
+ // information about the metadata. It's possible for this to be null.
+ const void* pRawData;
+
+ // The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL.
+ uint32_t rawDataSize;
+
+ union
+ {
+ drflac_streaminfo streaminfo;
+
+ struct
+ {
+ int unused;
+ } padding;
+
+ struct
+ {
+ uint32_t id;
+ const void* pData;
+ uint32_t dataSize;
+ } application;
+
+ struct
+ {
+ uint32_t seekpointCount;
+ const drflac_seekpoint* pSeekpoints;
+ } seektable;
+
+ struct
+ {
+ uint32_t vendorLength;
+ const char* vendor;
+ uint32_t commentCount;
+ const char* comments;
+ } vorbis_comment;
+
+ struct
+ {
+ char catalog[128];
+ uint64_t leadInSampleCount;
+ dr_bool32 isCD;
+ uint8_t trackCount;
+ const uint8_t* pTrackData;
+ } cuesheet;
+
+ struct
+ {
+ uint32_t type;
+ uint32_t mimeLength;
+ const char* mime;
+ uint32_t descriptionLength;
+ const char* description;
+ uint32_t width;
+ uint32_t height;
+ uint32_t colorDepth;
+ uint32_t indexColorCount;
+ uint32_t pictureDataSize;
+ const uint8_t* pPictureData;
+ } picture;
+ } data;
+
+} drflac_metadata;
+
+
+// Callback for when data needs to be read from the client.
+//
+// pUserData [in] The user data that was passed to drflac_open() and family.
+// pBufferOut [out] The output buffer.
+// bytesToRead [in] The number of bytes to read.
+//
+// Returns the number of bytes actually read.
+typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
+
+// Callback for when data needs to be seeked.
+//
+// pUserData [in] The user data that was passed to drflac_open() and family.
+// offset [in] The number of bytes to move, relative to the origin. Will never be negative.
+// origin [in] The origin of the seek - the current position or the start of the stream.
+//
+// Returns whether or not the seek was successful.
+//
+// The offset will never be negative. Whether or not it is relative to the beginning or current position is determined
+// by the "origin" parameter which will be either drflac_seek_origin_start or drflac_seek_origin_current.
+typedef dr_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
+
+// Callback for when a metadata block is read.
+//
+// pUserData [in] The user data that was passed to drflac_open() and family.
+// pMetadata [in] A pointer to a structure containing the data of the metadata block.
+//
+// Use pMetadata->type to determine which metadata block is being handled and how to read the data.
+typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata);
+
+
+// Structure for internal use. Only used for decoders opened with drflac_open_memory.
+typedef struct
+{
+ const uint8_t* data;
+ size_t dataSize;
+ size_t currentReadPos;
+} drflac__memory_stream;
+
+// Structure for internal use. Used for bit streaming.
+typedef struct
+{
+ // The function to call when more data needs to be read.
+ drflac_read_proc onRead;
+
+ // The function to call when the current read position needs to be moved.
+ drflac_seek_proc onSeek;
+
+ // The user data to pass around to onRead and onSeek.
+ void* pUserData;
+
+
+ // The number of unaligned bytes in the L2 cache. This will always be 0 until the end of the stream is hit. At the end of the
+ // stream there will be a number of bytes that don't cleanly fit in an L1 cache line, so we use this variable to know whether
+ // or not the bistreamer needs to run on a slower path to read those last bytes. This will never be more than sizeof(drflac_cache_t).
+ size_t unalignedByteCount;
+
+ // The content of the unaligned bytes.
+ drflac_cache_t unalignedCache;
+
+ // The index of the next valid cache line in the "L2" cache.
+ size_t nextL2Line;
+
+ // The number of bits that have been consumed by the cache. This is used to determine how many valid bits are remaining.
+ size_t consumedBits;
+
+ // The cached data which was most recently read from the client. There are two levels of cache. Data flows as such:
+ // Client -> L2 -> L1. The L2 -> L1 movement is aligned and runs on a fast path in just a few instructions.
+ drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)];
+ drflac_cache_t cache;
+
+} drflac_bs;
+
+typedef struct
+{
+ // The type of the subframe: SUBFRAME_CONSTANT, SUBFRAME_VERBATIM, SUBFRAME_FIXED or SUBFRAME_LPC.
+ uint8_t subframeType;
+
+ // The number of wasted bits per sample as specified by the sub-frame header.
+ uint8_t wastedBitsPerSample;
+
+ // The order to use for the prediction stage for SUBFRAME_FIXED and SUBFRAME_LPC.
+ uint8_t lpcOrder;
+
+ // The number of bits per sample for this subframe. This is not always equal to the current frame's bit per sample because
+ // an extra bit is required for side channels when interchannel decorrelation is being used.
+ uint32_t bitsPerSample;
+
+ // A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData, or
+ // NULL if the heap is not being used. Note that it's a signed 32-bit integer for each value.
+ int32_t* pDecodedSamples;
+
+} drflac_subframe;
+
+typedef struct
+{
+ // If the stream uses variable block sizes, this will be set to the index of the first sample. If fixed block sizes are used, this will
+ // always be set to 0.
+ uint64_t sampleNumber;
+
+ // If the stream uses fixed block sizes, this will be set to the frame number. If variable block sizes are used, this will always be 0.
+ uint32_t frameNumber;
+
+ // The sample rate of this frame.
+ uint32_t sampleRate;
+
+ // The number of samples in each sub-frame within this frame.
+ uint16_t blockSize;
+
+ // The channel assignment of this frame. This is not always set to the channel count. If interchannel decorrelation is being used this
+ // will be set to DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE, DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE or DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE.
+ uint8_t channelAssignment;
+
+ // The number of bits per sample within this frame.
+ uint8_t bitsPerSample;
+
+ // The frame's CRC. This is set, but unused at the moment.
+ uint8_t crc8;
+
+} drflac_frame_header;
+
+typedef struct
+{
+ // The header.
+ drflac_frame_header header;
+
+ // The number of samples left to be read in this frame. This is initially set to the block size multiplied by the channel count. As samples
+ // are read, this will be decremented. When it reaches 0, the decoder will see this frame as fully consumed and load the next frame.
+ uint32_t samplesRemaining;
+
+ // The list of sub-frames within the frame. There is one sub-frame for each channel, and there's a maximum of 8 channels.
+ drflac_subframe subframes[8];
+
+} drflac_frame;
+
+typedef struct
+{
+ // The function to call when a metadata block is read.
+ drflac_meta_proc onMeta;
+
+ // The user data posted to the metadata callback function.
+ void* pUserDataMD;
+
+
+ // The sample rate. Will be set to something like 44100.
+ uint32_t sampleRate;
+
+ // The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. Maximum 8. This is set based on the
+ // value specified in the STREAMINFO block.
+ uint8_t channels;
+
+ // The bits per sample. Will be set to somthing like 16, 24, etc.
+ uint8_t bitsPerSample;
+
+ // The maximum block size, in samples. This number represents the number of samples in each channel (not combined).
+ uint16_t maxBlockSize;
+
+ // The total number of samples making up the stream. This includes every channel. For example, if the stream has 2 channels,
+ // with each channel having a total of 4096, this value will be set to 2*4096 = 8192. Can be 0 in which case it's still a
+ // valid stream, but just means the total sample count is unknown. Likely the case with streams like internet radio.
+ uint64_t totalSampleCount;
+
+
+ // The container type. This is set based on whether or not the decoder was opened from a native or Ogg stream.
+ drflac_container container;
+
+
+ // The position of the seektable in the file.
+ uint64_t seektablePos;
+
+ // The size of the seektable.
+ uint32_t seektableSize;
+
+
+ // Information about the frame the decoder is currently sitting on.
+ drflac_frame currentFrame;
+
+ // The position of the first frame in the stream. This is only ever used for seeking.
+ uint64_t firstFramePos;
+
+
+ // A hack to avoid a malloc() when opening a decoder with drflac_open_memory().
+ drflac__memory_stream memoryStream;
+
+
+
+ // A pointer to the decoded sample data. This is an offset of pExtraData.
+ int32_t* pDecodedSamples;
+
+
+ // The bit streamer. The raw FLAC data is fed through this object.
+ drflac_bs bs;
+
+ // Variable length extra data. We attach this to the end of the object so we avoid unnecessary mallocs.
+ uint8_t pExtraData[1];
+
+} drflac;
+
+
+// Opens a FLAC decoder.
+//
+// onRead [in] The function to call when data needs to be read from the client.
+// onSeek [in] The function to call when the read position of the client data needs to move.
+// pUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek.
+//
+// Returns a pointer to an object representing the decoder.
+//
+// Close the decoder with drflac_close().
+//
+// This function will automatically detect whether or not you are attempting to open a native or Ogg encapsulated
+// FLAC, both of which should work seamlessly without any manual intervention. Ogg encapsulation also works with
+// multiplexed streams which basically means it can play FLAC encoded audio tracks in videos.
+//
+// This is the lowest level function for opening a FLAC stream. You can also use drflac_open_file() and drflac_open_memory()
+// to open the stream from a file or from a block of memory respectively.
+//
+// The STREAMINFO block must be present for this to succeed.
+//
+// See also: drflac_open_file(), drflac_open_memory(), drflac_open_with_metadata(), drflac_close()
+drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData);
+
+// Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.).
+//
+// onRead [in] The function to call when data needs to be read from the client.
+// onSeek [in] The function to call when the read position of the client data needs to move.
+// onMeta [in] The function to call for every metadata block.
+// pUserData [in, optional] A pointer to application defined data that will be passed to onRead, onSeek and onMeta.
+//
+// Returns a pointer to an object representing the decoder.
+//
+// Close the decoder with drflac_close().
+//
+// This is slower than drflac_open(), so avoid this one if you don't need metadata. Internally, this will do a malloc()
+// and free() for every metadata block except for STREAMINFO and PADDING blocks.
+//
+// The caller is notified of the metadata via the onMeta callback. All metadata blocks with be handled before the function
+// returns.
+//
+// See also: drflac_open_file_with_metadata(), drflac_open_memory_with_metadata(), drflac_open(), drflac_close()
+drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData);
+
+// Closes the given FLAC decoder.
+//
+// pFlac [in] The decoder to close.
+//
+// This will destroy the decoder object.
+void drflac_close(drflac* pFlac);
+
+
+// Reads sample data from the given FLAC decoder, output as interleaved signed 32-bit PCM.
+//
+// pFlac [in] The decoder.
+// samplesToRead [in] The number of samples to read.
+// pBufferOut [out, optional] A pointer to the buffer that will receive the decoded samples.
+//
+// Returns the number of samples actually read.
+//
+// pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of samples
+// seeked.
+uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* pBufferOut);
+
+// Same as drflac_read_s32(), except outputs samples as 16-bit integer PCM rather than 32-bit. Note
+// that this is lossey.
+uint64_t drflac_read_s16(drflac* pFlac, uint64_t samplesToRead, int16_t* pBufferOut);
+
+// Seeks to the sample at the given index.
+//
+// pFlac [in] The decoder.
+// sampleIndex [in] The index of the sample to seek to. See notes below.
+//
+// Returns DR_TRUE if successful; DR_FALSE otherwise.
+//
+// The sample index is based on interleaving. In a stereo stream, for example, the sample at index 0 is the first sample
+// in the left channel; the sample at index 1 is the first sample on the right channel, and so on.
+//
+// When seeking, you will likely want to ensure it's rounded to a multiple of the channel count. You can do this with
+// something like drflac_seek_to_sample(pFlac, (mySampleIndex + (mySampleIndex % pFlac->channels)))
+dr_bool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex);
+
+
+
+#ifndef DR_FLAC_NO_STDIO
+// Opens a FLAC decoder from the file at the given path.
+//
+// filename [in] The path of the file to open, either absolute or relative to the current directory.
+//
+// Returns a pointer to an object representing the decoder.
+//
+// Close the decoder with drflac_close().
+//
+// This will hold a handle to the file until the decoder is closed with drflac_close(). Some platforms will restrict the
+// number of files a process can have open at any given time, so keep this mind if you have many decoders open at the
+// same time.
+//
+// See also: drflac_open(), drflac_open_file_with_metadata(), drflac_close()
+drflac* drflac_open_file(const char* filename);
+
+// Opens a FLAC decoder from the file at the given path and notifies the caller of the metadata chunks (album art, etc.)
+//
+// Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled.
+drflac* drflac_open_file_with_metadata(const char* filename, drflac_meta_proc onMeta, void* pUserData);
+#endif
+
+// Opens a FLAC decoder from a pre-allocated block of memory
+//
+// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
+// the lifetime of the decoder.
+drflac* drflac_open_memory(const void* data, size_t dataSize);
+
+// Opens a FLAC decoder from a pre-allocated block of memory and notifies the caller of the metadata chunks (album art, etc.)
+//
+// Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled.
+drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drflac_meta_proc onMeta, void* pUserData);
+
+
+
+//// High Level APIs ////
+
+// Opens a FLAC stream from the given callbacks and fully decodes it in a single operation. The return value is a
+// pointer to the sample data as interleaved signed 32-bit PCM. The returned data must be freed with drflac_free().
+//
+// Sometimes a FLAC file won't keep track of the total sample count. In this situation the function will continuously
+// read samples into a dynamically sized buffer on the heap until no samples are left.
+//
+// Do not call this function on a broadcast type of stream (like internet radio streams and whatnot).
+int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+int16_t* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+
+#ifndef DR_FLAC_NO_STDIO
+// Same as drflac_open_and_decode_s32() except opens the decoder from a file.
+int32_t* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+int16_t* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+#endif
+
+// Same as drflac_open_and_decode_s32() except opens the decoder from a block of memory.
+int32_t* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+int16_t* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+
+// Frees data returned by drflac_open_and_decode_*().
+void drflac_free(void* pSampleDataReturnedByOpenAndDecode);
+
+
+// Structure representing an iterator for vorbis comments in a VORBIS_COMMENT metadata block.
+typedef struct
+{
+ uint32_t countRemaining;
+ const char* pRunningData;
+} drflac_vorbis_comment_iterator;
+
+// Initializes a vorbis comment iterator. This can be used for iterating over the vorbis comments in a VORBIS_COMMENT
+// metadata block.
+void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, uint32_t commentCount, const char* pComments);
+
+// Goes to the next vorbis comment in the given iterator. If null is returned it means there are no more comments. The
+// returned string is NOT null terminated.
+const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, uint32_t* pCommentLengthOut);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif //dr_flac_h
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// IMPLEMENTATION
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifdef DR_FLAC_IMPLEMENTATION
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef _MSC_VER
+#include <intrin.h> // For _byteswap_ulong and _byteswap_uint64
+#endif
+
+#ifdef __linux__
+#define _BSD_SOURCE
+#include <endian.h>
+#endif
+
+#ifdef _MSC_VER
+#define DRFLAC_INLINE __forceinline
+#else
+#define DRFLAC_INLINE inline
+#endif
+
+#define DRFLAC_SUBFRAME_CONSTANT 0
+#define DRFLAC_SUBFRAME_VERBATIM 1
+#define DRFLAC_SUBFRAME_FIXED 8
+#define DRFLAC_SUBFRAME_LPC 32
+#define DRFLAC_SUBFRAME_RESERVED 255
+
+#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE 0
+#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 1
+
+#define DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT 0
+#define DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE 8
+#define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9
+#define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10
+
+
+//// Endian Management ////
+static DRFLAC_INLINE dr_bool32 drflac__is_little_endian()
+{
+ int n = 1;
+ return (*(char*)&n) == 1;
+}
+
+static DRFLAC_INLINE uint16_t drflac__swap_endian_uint16(uint16_t n)
+{
+#ifdef _MSC_VER
+ return _byteswap_ushort(n);
+#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+ return __builtin_bswap16(n);
+#else
+ return ((n & 0xFF00) >> 8) |
+ ((n & 0x00FF) << 8);
+#endif
+}
+
+static DRFLAC_INLINE uint32_t drflac__swap_endian_uint32(uint32_t n)
+{
+#ifdef _MSC_VER
+ return _byteswap_ulong(n);
+#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+ return __builtin_bswap32(n);
+#else
+ return ((n & 0xFF000000) >> 24) |
+ ((n & 0x00FF0000) >> 8) |
+ ((n & 0x0000FF00) << 8) |
+ ((n & 0x000000FF) << 24);
+#endif
+}
+
+static DRFLAC_INLINE uint64_t drflac__swap_endian_uint64(uint64_t n)
+{
+#ifdef _MSC_VER
+ return _byteswap_uint64(n);
+#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+ return __builtin_bswap64(n);
+#else
+ return ((n & 0xFF00000000000000ULL) >> 56) |
+ ((n & 0x00FF000000000000ULL) >> 40) |
+ ((n & 0x0000FF0000000000ULL) >> 24) |
+ ((n & 0x000000FF00000000ULL) >> 8) |
+ ((n & 0x00000000FF000000ULL) << 8) |
+ ((n & 0x0000000000FF0000ULL) << 24) |
+ ((n & 0x000000000000FF00ULL) << 40) |
+ ((n & 0x00000000000000FFULL) << 56);
+#endif
+}
+
+static DRFLAC_INLINE uint16_t drflac__be2host_16(uint16_t n)
+{
+#ifdef __linux__
+ return be16toh(n);
+#else
+ if (drflac__is_little_endian()) {
+ return drflac__swap_endian_uint16(n);
+ }
+
+ return n;
+#endif
+}
+
+static DRFLAC_INLINE uint32_t drflac__be2host_32(uint32_t n)
+{
+#ifdef __linux__
+ return be32toh(n);
+#else
+ if (drflac__is_little_endian()) {
+ return drflac__swap_endian_uint32(n);
+ }
+
+ return n;
+#endif
+}
+
+static DRFLAC_INLINE uint64_t drflac__be2host_64(uint64_t n)
+{
+#ifdef __linux__
+ return be64toh(n);
+#else
+ if (drflac__is_little_endian()) {
+ return drflac__swap_endian_uint64(n);
+ }
+
+ return n;
+#endif
+}
+
+
+static DRFLAC_INLINE uint32_t drflac__le2host_32(uint32_t n)
+{
+#ifdef __linux__
+ return le32toh(n);
+#else
+ if (!drflac__is_little_endian()) {
+ return drflac__swap_endian_uint32(n);
+ }
+
+ return n;
+#endif
+}
+
+
+#ifdef DRFLAC_64BIT
+#define drflac__be2host__cache_line drflac__be2host_64
+#else
+#define drflac__be2host__cache_line drflac__be2host_32
+#endif
+
+
+// BIT READING ATTEMPT #2
+//
+// This uses a 32- or 64-bit bit-shifted cache - as bits are read, the cache is shifted such that the first valid bit is sitting
+// on the most significant bit. It uses the notion of an L1 and L2 cache (borrowed from CPU architecture), where the L1 cache
+// is a 32- or 64-bit unsigned integer (depending on whether or not a 32- or 64-bit build is being compiled) and the L2 is an
+// array of "cache lines", with each cache line being the same size as the L1. The L2 is a buffer of about 4KB and is where data
+// from onRead() is read into.
+#define DRFLAC_CACHE_L1_SIZE_BYTES(bs) (sizeof((bs)->cache))
+#define DRFLAC_CACHE_L1_SIZE_BITS(bs) (sizeof((bs)->cache)*8)
+#define DRFLAC_CACHE_L1_BITS_REMAINING(bs) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - ((bs)->consumedBits))
+#ifdef DRFLAC_64BIT
+#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((uint64_t)-1LL) >> (_bitCount)))
+#else
+#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((uint32_t)-1) >> (_bitCount)))
+#endif
+#define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount))
+#define DRFLAC_CACHE_L1_SELECT(bs, _bitCount) (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount))
+#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SELECT((bs), _bitCount) >> DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), _bitCount))
+#define DRFLAC_CACHE_L2_SIZE_BYTES(bs) (sizeof((bs)->cacheL2))
+#define DRFLAC_CACHE_L2_LINE_COUNT(bs) (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0]))
+#define DRFLAC_CACHE_L2_LINES_REMAINING(bs) (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line)
+
+static DRFLAC_INLINE dr_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
+{
+ // Fast path. Try loading straight from L2.
+ if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
+ bs->cache = bs->cacheL2[bs->nextL2Line++];
+ return DR_TRUE;
+ }
+
+ // If we get here it means we've run out of data in the L2 cache. We'll need to fetch more from the client, if there's
+ // any left.
+ if (bs->unalignedByteCount > 0) {
+ return DR_FALSE; // If we have any unaligned bytes it means there's not more aligned bytes left in the client.
+ }
+
+ size_t bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs));
+
+ bs->nextL2Line = 0;
+ if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) {
+ bs->cache = bs->cacheL2[bs->nextL2Line++];
+ return DR_TRUE;
+ }
+
+
+ // If we get here it means we were unable to retrieve enough data to fill the entire L2 cache. It probably
+ // means we've just reached the end of the file. We need to move the valid data down to the end of the buffer
+ // and adjust the index of the next line accordingly. Also keep in mind that the L2 cache must be aligned to
+ // the size of the L1 so we'll need to seek backwards by any misaligned bytes.
+ size_t alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs);
+
+ // We need to keep track of any unaligned bytes for later use.
+ bs->unalignedByteCount = bytesRead - (alignedL1LineCount * DRFLAC_CACHE_L1_SIZE_BYTES(bs));
+ if (bs->unalignedByteCount > 0) {
+ bs->unalignedCache = bs->cacheL2[alignedL1LineCount];
+ }
+
+ if (alignedL1LineCount > 0)
+ {
+ size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount;
+ for (size_t i = alignedL1LineCount; i > 0; --i) {
+ bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1];
+ }
+
+ bs->nextL2Line = offset;
+ bs->cache = bs->cacheL2[bs->nextL2Line++];
+ return DR_TRUE;
+ }
+ else
+ {
+ // If we get into this branch it means we weren't able to load any L1-aligned data.
+ bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs);
+ return DR_FALSE;
+ }
+}
+
+static dr_bool32 drflac__reload_cache(drflac_bs* bs)
+{
+ // Fast path. Try just moving the next value in the L2 cache to the L1 cache.
+ if (drflac__reload_l1_cache_from_l2(bs)) {
+ bs->cache = drflac__be2host__cache_line(bs->cache);
+ bs->consumedBits = 0;
+ return DR_TRUE;
+ }
+
+ // Slow path.
+
+ // If we get here it means we have failed to load the L1 cache from the L2. Likely we've just reached the end of the stream and the last
+ // few bytes did not meet the alignment requirements for the L2 cache. In this case we need to fall back to a slower path and read the
+ // data from the unaligned cache.
+ size_t bytesRead = bs->unalignedByteCount;
+ if (bytesRead == 0) {
+ return DR_FALSE;
+ }
+
+ assert(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(bs));
+ bs->consumedBits = (DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8;
+
+ bs->cache = drflac__be2host__cache_line(bs->unalignedCache);
+ bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs->consumedBits); // <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property.
+ return DR_TRUE;
+}
+
+static void drflac__reset_cache(drflac_bs* bs)
+{
+ bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); // <-- This clears the L2 cache.
+ bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); // <-- This clears the L1 cache.
+ bs->cache = 0;
+ bs->unalignedByteCount = 0; // <-- This clears the trailing unaligned bytes.
+ bs->unalignedCache = 0;
+}
+
+static dr_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
+{
+ if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
+ bs->consumedBits += bitsToSeek;
+ bs->cache <<= bitsToSeek;
+ return DR_TRUE;
+ } else {
+ // It straddles the cached data. This function isn't called too frequently so I'm favouring simplicity here.
+ bitsToSeek -= DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+ bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+ bs->cache = 0;
+
+ size_t wholeBytesRemaining = bitsToSeek/8;
+ if (wholeBytesRemaining > 0)
+ {
+ // The next bytes to seek will be located in the L2 cache. The problem is that the L2 cache is not byte aligned,
+ // but rather DRFLAC_CACHE_L1_SIZE_BYTES aligned (usually 4 or 8). If, for example, the number of bytes to seek is
+ // 3, we'll need to handle it in a special way.
+ size_t wholeCacheLinesRemaining = wholeBytesRemaining / DRFLAC_CACHE_L1_SIZE_BYTES(bs);
+ if (wholeCacheLinesRemaining < DRFLAC_CACHE_L2_LINES_REMAINING(bs))
+ {
+ wholeBytesRemaining -= wholeCacheLinesRemaining * DRFLAC_CACHE_L1_SIZE_BYTES(bs);
+ bitsToSeek -= wholeCacheLinesRemaining * DRFLAC_CACHE_L1_SIZE_BITS(bs);
+ bs->nextL2Line += wholeCacheLinesRemaining;
+ }
+ else
+ {
+ wholeBytesRemaining -= DRFLAC_CACHE_L2_LINES_REMAINING(bs) * DRFLAC_CACHE_L1_SIZE_BYTES(bs);
+ bitsToSeek -= DRFLAC_CACHE_L2_LINES_REMAINING(bs) * DRFLAC_CACHE_L1_SIZE_BITS(bs);
+ bs->nextL2Line += DRFLAC_CACHE_L2_LINES_REMAINING(bs);
+
+ if (wholeBytesRemaining > 0) {
+ bs->onSeek(bs->pUserData, (int)wholeBytesRemaining, drflac_seek_origin_current);
+ bitsToSeek -= wholeBytesRemaining*8;
+ }
+ }
+ }
+
+
+ if (bitsToSeek > 0) {
+ if (!drflac__reload_cache(bs)) {
+ return DR_FALSE;
+ }
+
+ return drflac__seek_bits(bs, bitsToSeek);
+ }
+
+ return DR_TRUE;
+ }
+}
+
+static dr_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, uint32_t* pResultOut)
+{
+ assert(bs != NULL);
+ assert(pResultOut != NULL);
+ assert(bitCount > 0);
+ assert(bitCount <= 32);
+
+ if (bs->consumedBits == DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
+ if (!drflac__reload_cache(bs)) {
+ return DR_FALSE;
+ }
+ }
+
+ if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
+ if (bitCount < DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
+ *pResultOut = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount);
+ bs->consumedBits += bitCount;
+ bs->cache <<= bitCount;
+ } else {
+ *pResultOut = (uint32_t)bs->cache;
+ bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);
+ bs->cache = 0;
+ }
+ return DR_TRUE;
+ } else {
+ // It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them.
+ size_t bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+ size_t bitCountLo = bitCount - bitCountHi;
+ uint32_t resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi);
+
+ if (!drflac__reload_cache(bs)) {
+ return DR_FALSE;
+ }
+
+ *pResultOut = (resultHi << bitCountLo) | DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo);
+ bs->consumedBits += bitCountLo;
+ bs->cache <<= bitCountLo;
+ return DR_TRUE;
+ }
+}
+
+static dr_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, int32_t* pResult)
+{
+ assert(bs != NULL);
+ assert(pResult != NULL);
+ assert(bitCount > 0);
+ assert(bitCount <= 32);
+
+ uint32_t result;
+ if (!drflac__read_uint32(bs, bitCount, &result)) {
+ return DR_FALSE;
+ }
+
+ uint32_t signbit = ((result >> (bitCount-1)) & 0x01);
+ result |= (~signbit + 1) << bitCount;
+
+ *pResult = (int32_t)result;
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, uint64_t* pResultOut)
+{
+ assert(bitCount <= 64);
+ assert(bitCount > 32);
+
+ uint32_t resultHi;
+ if (!drflac__read_uint32(bs, bitCount - 32, &resultHi)) {
+ return DR_FALSE;
+ }
+
+ uint32_t resultLo;
+ if (!drflac__read_uint32(bs, 32, &resultLo)) {
+ return DR_FALSE;
+ }
+
+ *pResultOut = (((uint64_t)resultHi) << 32) | ((uint64_t)resultLo);
+ return DR_TRUE;
+}
+
+// Function below is unused, but leaving it here in case I need to quickly add it again.
+#if 0
+static dr_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, int64_t* pResultOut)
+{
+ assert(bitCount <= 64);
+
+ uint64_t result;
+ if (!drflac__read_uint64(bs, bitCount, &result)) {
+ return DR_FALSE;
+ }
+
+ uint64_t signbit = ((result >> (bitCount-1)) & 0x01);
+ result |= (~signbit + 1) << bitCount;
+
+ *pResultOut = (int64_t)result;
+ return DR_TRUE;
+}
+#endif
+
+static dr_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, uint16_t* pResult)
+{
+ assert(bs != NULL);
+ assert(pResult != NULL);
+ assert(bitCount > 0);
+ assert(bitCount <= 16);
+
+ uint32_t result;
+ if (!drflac__read_uint32(bs, bitCount, &result)) {
+ return DR_FALSE;
+ }
+
+ *pResult = (uint16_t)result;
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, int16_t* pResult)
+{
+ assert(bs != NULL);
+ assert(pResult != NULL);
+ assert(bitCount > 0);
+ assert(bitCount <= 16);
+
+ int32_t result;
+ if (!drflac__read_int32(bs, bitCount, &result)) {
+ return DR_FALSE;
+ }
+
+ *pResult = (int16_t)result;
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, uint8_t* pResult)
+{
+ assert(bs != NULL);
+ assert(pResult != NULL);
+ assert(bitCount > 0);
+ assert(bitCount <= 8);
+
+ uint32_t result;
+ if (!drflac__read_uint32(bs, bitCount, &result)) {
+ return DR_FALSE;
+ }
+
+ *pResult = (uint8_t)result;
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, int8_t* pResult)
+{
+ assert(bs != NULL);
+ assert(pResult != NULL);
+ assert(bitCount > 0);
+ assert(bitCount <= 8);
+
+ int32_t result;
+ if (!drflac__read_int32(bs, bitCount, &result)) {
+ return DR_FALSE;
+ }
+
+ *pResult = (int8_t)result;
+ return DR_TRUE;
+}
+
+
+static inline dr_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut)
+{
+ unsigned int zeroCounter = 0;
+ while (bs->cache == 0) {
+ zeroCounter += (unsigned int)DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+ if (!drflac__reload_cache(bs)) {
+ return DR_FALSE;
+ }
+ }
+
+ // At this point the cache should not be zero, in which case we know the first set bit should be somewhere in here. There is
+ // no need for us to perform any cache reloading logic here which should make things much faster.
+ assert(bs->cache != 0);
+
+ unsigned int bitOffsetTable[] = {
+ 0,
+ 4,
+ 3, 3,
+ 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1
+ };
+
+ unsigned int setBitOffsetPlus1 = bitOffsetTable[DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, 4)];
+ if (setBitOffsetPlus1 == 0) {
+ if (bs->cache == 1) {
+ setBitOffsetPlus1 = DRFLAC_CACHE_L1_SIZE_BITS(bs);
+ } else {
+ setBitOffsetPlus1 = 5;
+ for (;;)
+ {
+ if ((bs->cache & DRFLAC_CACHE_L1_SELECT(bs, setBitOffsetPlus1))) {
+ break;
+ }
+
+ setBitOffsetPlus1 += 1;
+ }
+ }
+ }
+
+ bs->consumedBits += setBitOffsetPlus1;
+ bs->cache <<= setBitOffsetPlus1;
+
+ *pOffsetOut = zeroCounter + setBitOffsetPlus1 - 1;
+ return DR_TRUE;
+}
+
+
+
+static dr_bool32 drflac__seek_to_byte(drflac_bs* bs, uint64_t offsetFromStart)
+{
+ assert(bs != NULL);
+ assert(offsetFromStart > 0);
+
+ // Seeking from the start is not quite as trivial as it sounds because the onSeek callback takes a signed 32-bit integer (which
+ // is intentional because it simplifies the implementation of the onSeek callbacks), however offsetFromStart is unsigned 64-bit.
+ // To resolve we just need to do an initial seek from the start, and then a series of offset seeks to make up the remainder.
+ if (offsetFromStart > 0x7FFFFFFF)
+ {
+ uint64_t bytesRemaining = offsetFromStart;
+ if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
+ return DR_FALSE;
+ }
+ bytesRemaining -= 0x7FFFFFFF;
+
+
+ while (bytesRemaining > 0x7FFFFFFF) {
+ if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ bytesRemaining -= 0x7FFFFFFF;
+ }
+
+
+ if (bytesRemaining > 0) {
+ if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+ }
+ else
+ {
+ if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, drflac_seek_origin_start)) {
+ return DR_FALSE;
+ }
+ }
+
+
+ // The cache should be reset to force a reload of fresh data from the client.
+ drflac__reset_cache(bs);
+ return DR_TRUE;
+}
+
+
+static dr_bool32 drflac__read_utf8_coded_number(drflac_bs* bs, uint64_t* pNumberOut)
+{
+ assert(bs != NULL);
+ assert(pNumberOut != NULL);
+
+ unsigned char utf8[7] = {0};
+ if (!drflac__read_uint8(bs, 8, utf8)) {
+ *pNumberOut = 0;
+ return DR_FALSE;
+ }
+
+ if ((utf8[0] & 0x80) == 0) {
+ *pNumberOut = utf8[0];
+ return DR_TRUE;
+ }
+
+ int byteCount = 1;
+ if ((utf8[0] & 0xE0) == 0xC0) {
+ byteCount = 2;
+ } else if ((utf8[0] & 0xF0) == 0xE0) {
+ byteCount = 3;
+ } else if ((utf8[0] & 0xF8) == 0xF0) {
+ byteCount = 4;
+ } else if ((utf8[0] & 0xFC) == 0xF8) {
+ byteCount = 5;
+ } else if ((utf8[0] & 0xFE) == 0xFC) {
+ byteCount = 6;
+ } else if ((utf8[0] & 0xFF) == 0xFE) {
+ byteCount = 7;
+ } else {
+ *pNumberOut = 0;
+ return DR_FALSE; // Bad UTF-8 encoding.
+ }
+
+ // Read extra bytes.
+ assert(byteCount > 1);
+
+ uint64_t result = (uint64_t)(utf8[0] & (0xFF >> (byteCount + 1)));
+ for (int i = 1; i < byteCount; ++i) {
+ if (!drflac__read_uint8(bs, 8, utf8 + i)) {
+ *pNumberOut = 0;
+ return DR_FALSE;
+ }
+
+ result = (result << 6) | (utf8[i] & 0x3F);
+ }
+
+ *pNumberOut = result;
+ return DR_TRUE;
+}
+
+
+
+static DRFLAC_INLINE dr_bool32 drflac__read_and_seek_rice(drflac_bs* bs, uint8_t m)
+{
+ unsigned int unused;
+ if (!drflac__seek_past_next_set_bit(bs, &unused)) {
+ return DR_FALSE;
+ }
+
+ if (m > 0) {
+ if (!drflac__seek_bits(bs, m)) {
+ return DR_FALSE;
+ }
+ }
+
+ return DR_TRUE;
+}
+
+
+// The next two functions are responsible for calculating the prediction.
+//
+// When the bits per sample is >16 we need to use 64-bit integer arithmetic because otherwise we'll run out of precision. It's
+// safe to assume this will be slower on 32-bit platforms so we use a more optimal solution when the bits per sample is <=16.
+static DRFLAC_INLINE int32_t drflac__calculate_prediction_32(uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples)
+{
+ assert(order <= 32);
+
+ // 32-bit version.
+
+ // VC++ optimizes this to a single jmp. I've not yet verified this for other compilers.
+ int32_t prediction = 0;
+
+ switch (order)
+ {
+ case 32: prediction += coefficients[31] * pDecodedSamples[-32];
+ case 31: prediction += coefficients[30] * pDecodedSamples[-31];
+ case 30: prediction += coefficients[29] * pDecodedSamples[-30];
+ case 29: prediction += coefficients[28] * pDecodedSamples[-29];
+ case 28: prediction += coefficients[27] * pDecodedSamples[-28];
+ case 27: prediction += coefficients[26] * pDecodedSamples[-27];
+ case 26: prediction += coefficients[25] * pDecodedSamples[-26];
+ case 25: prediction += coefficients[24] * pDecodedSamples[-25];
+ case 24: prediction += coefficients[23] * pDecodedSamples[-24];
+ case 23: prediction += coefficients[22] * pDecodedSamples[-23];
+ case 22: prediction += coefficients[21] * pDecodedSamples[-22];
+ case 21: prediction += coefficients[20] * pDecodedSamples[-21];
+ case 20: prediction += coefficients[19] * pDecodedSamples[-20];
+ case 19: prediction += coefficients[18] * pDecodedSamples[-19];
+ case 18: prediction += coefficients[17] * pDecodedSamples[-18];
+ case 17: prediction += coefficients[16] * pDecodedSamples[-17];
+ case 16: prediction += coefficients[15] * pDecodedSamples[-16];
+ case 15: prediction += coefficients[14] * pDecodedSamples[-15];
+ case 14: prediction += coefficients[13] * pDecodedSamples[-14];
+ case 13: prediction += coefficients[12] * pDecodedSamples[-13];
+ case 12: prediction += coefficients[11] * pDecodedSamples[-12];
+ case 11: prediction += coefficients[10] * pDecodedSamples[-11];
+ case 10: prediction += coefficients[ 9] * pDecodedSamples[-10];
+ case 9: prediction += coefficients[ 8] * pDecodedSamples[- 9];
+ case 8: prediction += coefficients[ 7] * pDecodedSamples[- 8];
+ case 7: prediction += coefficients[ 6] * pDecodedSamples[- 7];
+ case 6: prediction += coefficients[ 5] * pDecodedSamples[- 6];
+ case 5: prediction += coefficients[ 4] * pDecodedSamples[- 5];
+ case 4: prediction += coefficients[ 3] * pDecodedSamples[- 4];
+ case 3: prediction += coefficients[ 2] * pDecodedSamples[- 3];
+ case 2: prediction += coefficients[ 1] * pDecodedSamples[- 2];
+ case 1: prediction += coefficients[ 0] * pDecodedSamples[- 1];
+ }
+
+ return (int32_t)(prediction >> shift);
+}
+
+static DRFLAC_INLINE int32_t drflac__calculate_prediction_64(uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples)
+{
+ assert(order <= 32);
+
+ // 64-bit version.
+
+ // This method is faster on the 32-bit build when compiling with VC++. See note below.
+#ifndef DRFLAC_64BIT
+ int64_t prediction;
+ if (order == 8)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ prediction += coefficients[6] * (int64_t)pDecodedSamples[-7];
+ prediction += coefficients[7] * (int64_t)pDecodedSamples[-8];
+ }
+ else if (order == 7)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ prediction += coefficients[6] * (int64_t)pDecodedSamples[-7];
+ }
+ else if (order == 3)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ }
+ else if (order == 6)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ }
+ else if (order == 5)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ }
+ else if (order == 4)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ }
+ else if (order == 12)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ prediction += coefficients[6] * (int64_t)pDecodedSamples[-7];
+ prediction += coefficients[7] * (int64_t)pDecodedSamples[-8];
+ prediction += coefficients[8] * (int64_t)pDecodedSamples[-9];
+ prediction += coefficients[9] * (int64_t)pDecodedSamples[-10];
+ prediction += coefficients[10] * (int64_t)pDecodedSamples[-11];
+ prediction += coefficients[11] * (int64_t)pDecodedSamples[-12];
+ }
+ else if (order == 2)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ }
+ else if (order == 1)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ }
+ else if (order == 10)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ prediction += coefficients[6] * (int64_t)pDecodedSamples[-7];
+ prediction += coefficients[7] * (int64_t)pDecodedSamples[-8];
+ prediction += coefficients[8] * (int64_t)pDecodedSamples[-9];
+ prediction += coefficients[9] * (int64_t)pDecodedSamples[-10];
+ }
+ else if (order == 9)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ prediction += coefficients[6] * (int64_t)pDecodedSamples[-7];
+ prediction += coefficients[7] * (int64_t)pDecodedSamples[-8];
+ prediction += coefficients[8] * (int64_t)pDecodedSamples[-9];
+ }
+ else if (order == 11)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ prediction += coefficients[6] * (int64_t)pDecodedSamples[-7];
+ prediction += coefficients[7] * (int64_t)pDecodedSamples[-8];
+ prediction += coefficients[8] * (int64_t)pDecodedSamples[-9];
+ prediction += coefficients[9] * (int64_t)pDecodedSamples[-10];
+ prediction += coefficients[10] * (int64_t)pDecodedSamples[-11];
+ }
+ else
+ {
+ prediction = 0;
+ for (int j = 0; j < (int)order; ++j) {
+ prediction += coefficients[j] * (int64_t)pDecodedSamples[-j-1];
+ }
+ }
+#endif
+
+ // VC++ optimizes this to a single jmp instruction, but only the 64-bit build. The 32-bit build generates less efficient code for some
+ // reason. The ugly version above is faster so we'll just switch between the two depending on the target platform.
+#ifdef DRFLAC_64BIT
+ int64_t prediction = 0;
+
+ switch (order)
+ {
+ case 32: prediction += coefficients[31] * (int64_t)pDecodedSamples[-32];
+ case 31: prediction += coefficients[30] * (int64_t)pDecodedSamples[-31];
+ case 30: prediction += coefficients[29] * (int64_t)pDecodedSamples[-30];
+ case 29: prediction += coefficients[28] * (int64_t)pDecodedSamples[-29];
+ case 28: prediction += coefficients[27] * (int64_t)pDecodedSamples[-28];
+ case 27: prediction += coefficients[26] * (int64_t)pDecodedSamples[-27];
+ case 26: prediction += coefficients[25] * (int64_t)pDecodedSamples[-26];
+ case 25: prediction += coefficients[24] * (int64_t)pDecodedSamples[-25];
+ case 24: prediction += coefficients[23] * (int64_t)pDecodedSamples[-24];
+ case 23: prediction += coefficients[22] * (int64_t)pDecodedSamples[-23];
+ case 22: prediction += coefficients[21] * (int64_t)pDecodedSamples[-22];
+ case 21: prediction += coefficients[20] * (int64_t)pDecodedSamples[-21];
+ case 20: prediction += coefficients[19] * (int64_t)pDecodedSamples[-20];
+ case 19: prediction += coefficients[18] * (int64_t)pDecodedSamples[-19];
+ case 18: prediction += coefficients[17] * (int64_t)pDecodedSamples[-18];
+ case 17: prediction += coefficients[16] * (int64_t)pDecodedSamples[-17];
+ case 16: prediction += coefficients[15] * (int64_t)pDecodedSamples[-16];
+ case 15: prediction += coefficients[14] * (int64_t)pDecodedSamples[-15];
+ case 14: prediction += coefficients[13] * (int64_t)pDecodedSamples[-14];
+ case 13: prediction += coefficients[12] * (int64_t)pDecodedSamples[-13];
+ case 12: prediction += coefficients[11] * (int64_t)pDecodedSamples[-12];
+ case 11: prediction += coefficients[10] * (int64_t)pDecodedSamples[-11];
+ case 10: prediction += coefficients[ 9] * (int64_t)pDecodedSamples[-10];
+ case 9: prediction += coefficients[ 8] * (int64_t)pDecodedSamples[- 9];
+ case 8: prediction += coefficients[ 7] * (int64_t)pDecodedSamples[- 8];
+ case 7: prediction += coefficients[ 6] * (int64_t)pDecodedSamples[- 7];
+ case 6: prediction += coefficients[ 5] * (int64_t)pDecodedSamples[- 6];
+ case 5: prediction += coefficients[ 4] * (int64_t)pDecodedSamples[- 5];
+ case 4: prediction += coefficients[ 3] * (int64_t)pDecodedSamples[- 4];
+ case 3: prediction += coefficients[ 2] * (int64_t)pDecodedSamples[- 3];
+ case 2: prediction += coefficients[ 1] * (int64_t)pDecodedSamples[- 2];
+ case 1: prediction += coefficients[ 0] * (int64_t)pDecodedSamples[- 1];
+ }
+#endif
+
+ return (int32_t)(prediction >> shift);
+}
+
+
+// Reads and decodes a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes.
+//
+// This is the most frequently called function in the library. It does both the Rice decoding and the prediction in a single loop
+// iteration. The prediction is done at the end, and there's an annoying branch I'd like to avoid so the main function is defined
+// as a #define - sue me!
+#define DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(funcName, predictionFunc) \
+static dr_bool32 funcName (drflac_bs* bs, uint32_t count, uint8_t riceParam, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut) \
+{ \
+ assert(bs != NULL); \
+ assert(count > 0); \
+ assert(pSamplesOut != NULL); \
+ \
+ static unsigned int bitOffsetTable[] = { \
+ 0, \
+ 4, \
+ 3, 3, \
+ 2, 2, 2, 2, \
+ 1, 1, 1, 1, 1, 1, 1, 1 \
+ }; \
+ \
+ drflac_cache_t riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); \
+ drflac_cache_t resultHiShift = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParam; \
+ \
+ for (int i = 0; i < (int)count; ++i) \
+ { \
+ unsigned int zeroCounter = 0; \
+ while (bs->cache == 0) { \
+ zeroCounter += (unsigned int)DRFLAC_CACHE_L1_BITS_REMAINING(bs); \
+ if (!drflac__reload_cache(bs)) { \
+ return DR_FALSE; \
+ } \
+ } \
+ \
+ /* At this point the cache should not be zero, in which case we know the first set bit should be somewhere in here. There is \
+ no need for us to perform any cache reloading logic here which should make things much faster. */ \
+ assert(bs->cache != 0); \
+ unsigned int decodedRice; \
+ \
+ unsigned int setBitOffsetPlus1 = bitOffsetTable[DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, 4)]; \
+ if (setBitOffsetPlus1 > 0) { \
+ decodedRice = (zeroCounter + (setBitOffsetPlus1-1)) << riceParam; \
+ } else { \
+ if (bs->cache == 1) { \
+ setBitOffsetPlus1 = DRFLAC_CACHE_L1_SIZE_BITS(bs); \
+ decodedRice = (zeroCounter + (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1)) << riceParam; \
+ } else { \
+ setBitOffsetPlus1 = 5; \
+ for (;;) \
+ { \
+ if ((bs->cache & DRFLAC_CACHE_L1_SELECT(bs, setBitOffsetPlus1))) { \
+ decodedRice = (zeroCounter + (setBitOffsetPlus1-1)) << riceParam; \
+ break; \
+ } \
+ \
+ setBitOffsetPlus1 += 1; \
+ } \
+ } \
+ } \
+ \
+ \
+ unsigned int bitsLo = 0; \
+ unsigned int riceLength = setBitOffsetPlus1 + riceParam; \
+ if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) \
+ { \
+ bitsLo = (unsigned int)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> (DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceLength)); \
+ \
+ bs->consumedBits += riceLength; \
+ bs->cache <<= riceLength; \
+ } \
+ else \
+ { \
+ bs->consumedBits += riceLength; \
+ bs->cache <<= setBitOffsetPlus1; \
+ \
+ /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */ \
+ size_t bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); \
+ drflac_cache_t resultHi = bs->cache & riceParamMask; /* <-- This mask is OK because all bits after the first bits are always zero. */ \
+ \
+ \
+ if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { \
+ bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); \
+ } else { \
+ /* Slow path. We need to fetch more data from the client. */ \
+ if (!drflac__reload_cache(bs)) { \
+ return DR_FALSE; \
+ } \
+ } \
+ \
+ bitsLo = (unsigned int)((resultHi >> resultHiShift) | DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo)); \
+ bs->consumedBits = bitCountLo; \
+ bs->cache <<= bitCountLo; \
+ } \
+ \
+ decodedRice |= bitsLo; \
+ decodedRice = (decodedRice >> 1) ^ (~(decodedRice & 0x01) + 1); /* <-- Ah, much faster! :) */ \
+ /* \
+ if ((decodedRice & 0x01)) { \
+ decodedRice = ~(decodedRice >> 1); \
+ } else { \
+ decodedRice = (decodedRice >> 1); \
+ } \
+ */ \
+ \
+ /* In order to properly calculate the prediction when the bits per sample is >16 we need to do it using 64-bit arithmetic. We can assume this \
+ is probably going to be slower on 32-bit systems so we'll do a more optimized 32-bit version when the bits per sample is low enough.*/ \
+ pSamplesOut[i] = ((int)decodedRice + predictionFunc(order, shift, coefficients, pSamplesOut + i)); \
+ } \
+ \
+ return DR_TRUE; \
+} \
+
+DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(drflac__decode_samples_with_residual__rice_64, drflac__calculate_prediction_64)
+DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(drflac__decode_samples_with_residual__rice_32, drflac__calculate_prediction_32)
+
+
+// Reads and seeks past a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes.
+static dr_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, uint32_t count, uint8_t riceParam)
+{
+ assert(bs != NULL);
+ assert(count > 0);
+
+ for (uint32_t i = 0; i < count; ++i) {
+ if (!drflac__read_and_seek_rice(bs, riceParam)) {
+ return DR_FALSE;
+ }
+ }
+
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, uint32_t bitsPerSample, uint32_t count, uint8_t unencodedBitsPerSample, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut)
+{
+ assert(bs != NULL);
+ assert(count > 0);
+ assert(unencodedBitsPerSample > 0 && unencodedBitsPerSample <= 32);
+ assert(pSamplesOut != NULL);
+
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) {
+ return DR_FALSE;
+ }
+
+ if (bitsPerSample > 16) {
+ pSamplesOut[i] += drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i);
+ } else {
+ pSamplesOut[i] += drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i);
+ }
+ }
+
+ return DR_TRUE;
+}
+
+
+// Reads and decodes the residual for the sub-frame the decoder is currently sitting on. This function should be called
+// when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be ignored. The
+// <blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
+static dr_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, uint32_t bitsPerSample, uint32_t blockSize, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples)
+{
+ assert(bs != NULL);
+ assert(blockSize != 0);
+ assert(pDecodedSamples != NULL); // <-- Should we allow NULL, in which case we just seek past the residual rather than do a full decode?
+
+ uint8_t residualMethod;
+ if (!drflac__read_uint8(bs, 2, &residualMethod)) {
+ return DR_FALSE;
+ }
+
+ if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
+ return DR_FALSE; // Unknown or unsupported residual coding method.
+ }
+
+ // Ignore the first <order> values.
+ pDecodedSamples += order;
+
+
+ uint8_t partitionOrder;
+ if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
+ return DR_FALSE;
+ }
+
+
+ uint32_t samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
+ uint32_t partitionsRemaining = (1 << partitionOrder);
+ for (;;)
+ {
+ uint8_t riceParam = 0;
+ if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
+ if (!drflac__read_uint8(bs, 4, &riceParam)) {
+ return DR_FALSE;
+ }
+ if (riceParam == 16) {
+ riceParam = 0xFF;
+ }
+ } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
+ if (!drflac__read_uint8(bs, 5, &riceParam)) {
+ return DR_FALSE;
+ }
+ if (riceParam == 32) {
+ riceParam = 0xFF;
+ }
+ }
+
+ if (riceParam != 0xFF) {
+ if (bitsPerSample > 16) {
+ if (!drflac__decode_samples_with_residual__rice_64(bs, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) {
+ return DR_FALSE;
+ }
+ } else {
+ if (!drflac__decode_samples_with_residual__rice_32(bs, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) {
+ return DR_FALSE;
+ }
+ }
+ } else {
+ unsigned char unencodedBitsPerSample = 0;
+ if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
+ return DR_FALSE;
+ }
+
+ if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, order, shift, coefficients, pDecodedSamples)) {
+ return DR_FALSE;
+ }
+ }
+
+ pDecodedSamples += samplesInPartition;
+
+
+ if (partitionsRemaining == 1) {
+ break;
+ }
+
+ partitionsRemaining -= 1;
+ samplesInPartition = blockSize / (1 << partitionOrder);
+ }
+
+ return DR_TRUE;
+}
+
+// Reads and seeks past the residual for the sub-frame the decoder is currently sitting on. This function should be called
+// when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be set to 0. The
+// <blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
+static dr_bool32 drflac__read_and_seek_residual(drflac_bs* bs, uint32_t blockSize, uint32_t order)
+{
+ assert(bs != NULL);
+ assert(blockSize != 0);
+
+ uint8_t residualMethod;
+ if (!drflac__read_uint8(bs, 2, &residualMethod)) {
+ return DR_FALSE;
+ }
+
+ if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
+ return DR_FALSE; // Unknown or unsupported residual coding method.
+ }
+
+ uint8_t partitionOrder;
+ if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
+ return DR_FALSE;
+ }
+
+ uint32_t samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
+ uint32_t partitionsRemaining = (1 << partitionOrder);
+ for (;;)
+ {
+ uint8_t riceParam = 0;
+ if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
+ if (!drflac__read_uint8(bs, 4, &riceParam)) {
+ return DR_FALSE;
+ }
+ if (riceParam == 16) {
+ riceParam = 0xFF;
+ }
+ } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
+ if (!drflac__read_uint8(bs, 5, &riceParam)) {
+ return DR_FALSE;
+ }
+ if (riceParam == 32) {
+ riceParam = 0xFF;
+ }
+ }
+
+ if (riceParam != 0xFF) {
+ if (!drflac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) {
+ return DR_FALSE;
+ }
+ } else {
+ unsigned char unencodedBitsPerSample = 0;
+ if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
+ return DR_FALSE;
+ }
+
+ if (!drflac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) {
+ return DR_FALSE;
+ }
+ }
+
+
+ if (partitionsRemaining == 1) {
+ break;
+ }
+
+ partitionsRemaining -= 1;
+ samplesInPartition = blockSize / (1 << partitionOrder);
+ }
+
+ return DR_TRUE;
+}
+
+
+static dr_bool32 drflac__decode_samples__constant(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples)
+{
+ // Only a single sample needs to be decoded here.
+ int32_t sample;
+ if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
+ return DR_FALSE;
+ }
+
+ // We don't really need to expand this, but it does simplify the process of reading samples. If this becomes a performance issue (unlikely)
+ // we'll want to look at a more efficient way.
+ for (uint32_t i = 0; i < blockSize; ++i) {
+ pDecodedSamples[i] = sample;
+ }
+
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples)
+{
+ for (uint32_t i = 0; i < blockSize; ++i) {
+ int32_t sample;
+ if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
+ return DR_FALSE;
+ }
+
+ pDecodedSamples[i] = sample;
+ }
+
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__decode_samples__fixed(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples)
+{
+ short lpcCoefficientsTable[5][4] = {
+ {0, 0, 0, 0},
+ {1, 0, 0, 0},
+ {2, -1, 0, 0},
+ {3, -3, 1, 0},
+ {4, -6, 4, -1}
+ };
+
+ // Warm up samples and coefficients.
+ for (uint32_t i = 0; i < lpcOrder; ++i) {
+ int32_t sample;
+ if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
+ return DR_FALSE;
+ }
+
+ pDecodedSamples[i] = sample;
+ }
+
+
+ if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) {
+ return DR_FALSE;
+ }
+
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__decode_samples__lpc(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples)
+{
+ // Warm up samples.
+ for (uint8_t i = 0; i < lpcOrder; ++i) {
+ int32_t sample;
+ if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
+ return DR_FALSE;
+ }
+
+ pDecodedSamples[i] = sample;
+ }
+
+ uint8_t lpcPrecision;
+ if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
+ return DR_FALSE;
+ }
+ if (lpcPrecision == 15) {
+ return DR_FALSE; // Invalid.
+ }
+ lpcPrecision += 1;
+
+
+ int8_t lpcShift;
+ if (!drflac__read_int8(bs, 5, &lpcShift)) {
+ return DR_FALSE;
+ }
+
+
+ int16_t coefficients[32];
+ for (uint8_t i = 0; i < lpcOrder; ++i) {
+ if (!drflac__read_int16(bs, lpcPrecision, coefficients + i)) {
+ return DR_FALSE;
+ }
+ }
+
+ if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, coefficients, pDecodedSamples)) {
+ return DR_FALSE;
+ }
+
+ return DR_TRUE;
+}
+
+
+static dr_bool32 drflac__read_next_frame_header(drflac_bs* bs, uint8_t streaminfoBitsPerSample, drflac_frame_header* header)
+{
+ assert(bs != NULL);
+ assert(header != NULL);
+
+ // At the moment the sync code is as a form of basic validation. The CRC is stored, but is unused at the moment. This
+ // should probably be handled better in the future.
+
+ const uint32_t sampleRateTable[12] = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000};
+ const uint8_t bitsPerSampleTable[8] = {0, 8, 12, (uint8_t)-1, 16, 20, 24, (uint8_t)-1}; // -1 = reserved.
+
+ uint16_t syncCode = 0;
+ if (!drflac__read_uint16(bs, 14, &syncCode)) {
+ return DR_FALSE;
+ }
+
+ if (syncCode != 0x3FFE) {
+ // TODO: Try and recover by attempting to seek to and read the next frame?
+ return DR_FALSE;
+ }
+
+ uint8_t reserved;
+ if (!drflac__read_uint8(bs, 1, &reserved)) {
+ return DR_FALSE;
+ }
+
+ uint8_t blockingStrategy = 0;
+ if (!drflac__read_uint8(bs, 1, &blockingStrategy)) {
+ return DR_FALSE;
+ }
+
+
+
+ uint8_t blockSize = 0;
+ if (!drflac__read_uint8(bs, 4, &blockSize)) {
+ return DR_FALSE;
+ }
+
+ uint8_t sampleRate = 0;
+ if (!drflac__read_uint8(bs, 4, &sampleRate)) {
+ return DR_FALSE;
+ }
+
+ uint8_t channelAssignment = 0;
+ if (!drflac__read_uint8(bs, 4, &channelAssignment)) {
+ return DR_FALSE;
+ }
+
+ uint8_t bitsPerSample = 0;
+ if (!drflac__read_uint8(bs, 3, &bitsPerSample)) {
+ return DR_FALSE;
+ }
+
+ if (!drflac__read_uint8(bs, 1, &reserved)) {
+ return DR_FALSE;
+ }
+
+
+ dr_bool32 isVariableBlockSize = blockingStrategy == 1;
+ if (isVariableBlockSize) {
+ uint64_t sampleNumber;
+ if (!drflac__read_utf8_coded_number(bs, &sampleNumber)) {
+ return DR_FALSE;
+ }
+ header->frameNumber = 0;
+ header->sampleNumber = sampleNumber;
+ } else {
+ uint64_t frameNumber = 0;
+ if (!drflac__read_utf8_coded_number(bs, &frameNumber)) {
+ return DR_FALSE;
+ }
+ header->frameNumber = (uint32_t)frameNumber; // <-- Safe cast.
+ header->sampleNumber = 0;
+ }
+
+
+ if (blockSize == 1) {
+ header->blockSize = 192;
+ } else if (blockSize >= 2 && blockSize <= 5) {
+ header->blockSize = 576 * (1 << (blockSize - 2));
+ } else if (blockSize == 6) {
+ if (!drflac__read_uint16(bs, 8, &header->blockSize)) {
+ return DR_FALSE;
+ }
+ header->blockSize += 1;
+ } else if (blockSize == 7) {
+ if (!drflac__read_uint16(bs, 16, &header->blockSize)) {
+ return DR_FALSE;
+ }
+ header->blockSize += 1;
+ } else {
+ header->blockSize = 256 * (1 << (blockSize - 8));
+ }
+
+
+ if (sampleRate <= 11) {
+ header->sampleRate = sampleRateTable[sampleRate];
+ } else if (sampleRate == 12) {
+ if (!drflac__read_uint32(bs, 8, &header->sampleRate)) {
+ return DR_FALSE;
+ }
+ header->sampleRate *= 1000;
+ } else if (sampleRate == 13) {
+ if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
+ return DR_FALSE;
+ }
+ } else if (sampleRate == 14) {
+ if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
+ return DR_FALSE;
+ }
+ header->sampleRate *= 10;
+ } else {
+ return DR_FALSE; // Invalid.
+ }
+
+
+ header->channelAssignment = channelAssignment;
+
+ header->bitsPerSample = bitsPerSampleTable[bitsPerSample];
+ if (header->bitsPerSample == 0) {
+ header->bitsPerSample = streaminfoBitsPerSample;
+ }
+
+ if (drflac__read_uint8(bs, 8, &header->crc8) != 1) {
+ return DR_FALSE;
+ }
+
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe)
+{
+ uint8_t header;
+ if (!drflac__read_uint8(bs, 8, &header)) {
+ return DR_FALSE;
+ }
+
+ // First bit should always be 0.
+ if ((header & 0x80) != 0) {
+ return DR_FALSE;
+ }
+
+ int type = (header & 0x7E) >> 1;
+ if (type == 0) {
+ pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT;
+ } else if (type == 1) {
+ pSubframe->subframeType = DRFLAC_SUBFRAME_VERBATIM;
+ } else {
+ if ((type & 0x20) != 0) {
+ pSubframe->subframeType = DRFLAC_SUBFRAME_LPC;
+ pSubframe->lpcOrder = (type & 0x1F) + 1;
+ } else if ((type & 0x08) != 0) {
+ pSubframe->subframeType = DRFLAC_SUBFRAME_FIXED;
+ pSubframe->lpcOrder = (type & 0x07);
+ if (pSubframe->lpcOrder > 4) {
+ pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
+ pSubframe->lpcOrder = 0;
+ }
+ } else {
+ pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
+ }
+ }
+
+ if (pSubframe->subframeType == DRFLAC_SUBFRAME_RESERVED) {
+ return DR_FALSE;
+ }
+
+ // Wasted bits per sample.
+ pSubframe->wastedBitsPerSample = 0;
+ if ((header & 0x01) == 1) {
+ unsigned int wastedBitsPerSample;
+ if (!drflac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) {
+ return DR_FALSE;
+ }
+ pSubframe->wastedBitsPerSample = (unsigned char)wastedBitsPerSample + 1;
+ }
+
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, int32_t* pDecodedSamplesOut)
+{
+ assert(bs != NULL);
+ assert(frame != NULL);
+
+ drflac_subframe* pSubframe = frame->subframes + subframeIndex;
+ if (!drflac__read_subframe_header(bs, pSubframe)) {
+ return DR_FALSE;
+ }
+
+ // Side channels require an extra bit per sample. Took a while to figure that one out...
+ pSubframe->bitsPerSample = frame->header.bitsPerSample;
+ if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
+ pSubframe->bitsPerSample += 1;
+ } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
+ pSubframe->bitsPerSample += 1;
+ }
+
+ // Need to handle wasted bits per sample.
+ pSubframe->bitsPerSample -= pSubframe->wastedBitsPerSample;
+ pSubframe->pDecodedSamples = pDecodedSamplesOut;
+
+ switch (pSubframe->subframeType)
+ {
+ case DRFLAC_SUBFRAME_CONSTANT:
+ {
+ drflac__decode_samples__constant(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->pDecodedSamples);
+ } break;
+
+ case DRFLAC_SUBFRAME_VERBATIM:
+ {
+ drflac__decode_samples__verbatim(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->pDecodedSamples);
+ } break;
+
+ case DRFLAC_SUBFRAME_FIXED:
+ {
+ drflac__decode_samples__fixed(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->lpcOrder, pSubframe->pDecodedSamples);
+ } break;
+
+ case DRFLAC_SUBFRAME_LPC:
+ {
+ drflac__decode_samples__lpc(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->lpcOrder, pSubframe->pDecodedSamples);
+ } break;
+
+ default: return DR_FALSE;
+ }
+
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex)
+{
+ assert(bs != NULL);
+ assert(frame != NULL);
+
+ drflac_subframe* pSubframe = frame->subframes + subframeIndex;
+ if (!drflac__read_subframe_header(bs, pSubframe)) {
+ return DR_FALSE;
+ }
+
+ // Side channels require an extra bit per sample. Took a while to figure that one out...
+ pSubframe->bitsPerSample = frame->header.bitsPerSample;
+ if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
+ pSubframe->bitsPerSample += 1;
+ } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
+ pSubframe->bitsPerSample += 1;
+ }
+
+ // Need to handle wasted bits per sample.
+ pSubframe->bitsPerSample -= pSubframe->wastedBitsPerSample;
+ pSubframe->pDecodedSamples = NULL;
+ //pSubframe->pDecodedSamples = pFlac->pDecodedSamples + (pFlac->currentFrame.header.blockSize * subframeIndex);
+
+ switch (pSubframe->subframeType)
+ {
+ case DRFLAC_SUBFRAME_CONSTANT:
+ {
+ if (!drflac__seek_bits(bs, pSubframe->bitsPerSample)) {
+ return DR_FALSE;
+ }
+ } break;
+
+ case DRFLAC_SUBFRAME_VERBATIM:
+ {
+ unsigned int bitsToSeek = frame->header.blockSize * pSubframe->bitsPerSample;
+ if (!drflac__seek_bits(bs, bitsToSeek)) {
+ return DR_FALSE;
+ }
+ } break;
+
+ case DRFLAC_SUBFRAME_FIXED:
+ {
+ unsigned int bitsToSeek = pSubframe->lpcOrder * pSubframe->bitsPerSample;
+ if (!drflac__seek_bits(bs, bitsToSeek)) {
+ return DR_FALSE;
+ }
+
+ if (!drflac__read_and_seek_residual(bs, frame->header.blockSize, pSubframe->lpcOrder)) {
+ return DR_FALSE;
+ }
+ } break;
+
+ case DRFLAC_SUBFRAME_LPC:
+ {
+ unsigned int bitsToSeek = pSubframe->lpcOrder * pSubframe->bitsPerSample;
+ if (!drflac__seek_bits(bs, bitsToSeek)) {
+ return DR_FALSE;
+ }
+
+ unsigned char lpcPrecision;
+ if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
+ return DR_FALSE;
+ }
+ if (lpcPrecision == 15) {
+ return DR_FALSE; // Invalid.
+ }
+ lpcPrecision += 1;
+
+
+ bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; // +5 for shift.
+ if (!drflac__seek_bits(bs, bitsToSeek)) {
+ return DR_FALSE;
+ }
+
+ if (!drflac__read_and_seek_residual(bs, frame->header.blockSize, pSubframe->lpcOrder)) {
+ return DR_FALSE;
+ }
+ } break;
+
+ default: return DR_FALSE;
+ }
+
+ return DR_TRUE;
+}
+
+
+static DRFLAC_INLINE uint8_t drflac__get_channel_count_from_channel_assignment(int8_t channelAssignment)
+{
+ assert(channelAssignment <= 10);
+
+ uint8_t lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2};
+ return lookup[channelAssignment];
+}
+
+static dr_bool32 drflac__decode_frame(drflac* pFlac)
+{
+ // This function should be called while the stream is sitting on the first byte after the frame header.
+ memset(pFlac->currentFrame.subframes, 0, sizeof(pFlac->currentFrame.subframes));
+
+ int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
+ for (int i = 0; i < channelCount; ++i)
+ {
+ if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFrame, i, pFlac->pDecodedSamples + (pFlac->currentFrame.header.blockSize * i))) {
+ return DR_FALSE;
+ }
+ }
+
+ // At the end of the frame sits the padding and CRC. We don't use these so we can just seek past.
+ if (!drflac__seek_bits(&pFlac->bs, (DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7) + 16)) {
+ return DR_FALSE;
+ }
+
+
+ pFlac->currentFrame.samplesRemaining = pFlac->currentFrame.header.blockSize * channelCount;
+
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__seek_frame(drflac* pFlac)
+{
+ int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
+ for (int i = 0; i < channelCount; ++i)
+ {
+ if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFrame, i)) {
+ return DR_FALSE;
+ }
+ }
+
+ // Padding and CRC.
+ return drflac__seek_bits(&pFlac->bs, (DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7) + 16);
+}
+
+static dr_bool32 drflac__read_and_decode_next_frame(drflac* pFlac)
+{
+ assert(pFlac != NULL);
+
+ if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) {
+ return DR_FALSE;
+ }
+
+ return drflac__decode_frame(pFlac);
+}
+
+
+static void drflac__get_current_frame_sample_range(drflac* pFlac, uint64_t* pFirstSampleInFrameOut, uint64_t* pLastSampleInFrameOut)
+{
+ assert(pFlac != NULL);
+
+ unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
+
+ uint64_t firstSampleInFrame = pFlac->currentFrame.header.sampleNumber;
+ if (firstSampleInFrame == 0) {
+ firstSampleInFrame = pFlac->currentFrame.header.frameNumber * pFlac->maxBlockSize*channelCount;
+ }
+
+ uint64_t lastSampleInFrame = firstSampleInFrame + (pFlac->currentFrame.header.blockSize*channelCount);
+ if (lastSampleInFrame > 0) {
+ lastSampleInFrame -= 1; // Needs to be zero based.
+ }
+
+
+ if (pFirstSampleInFrameOut) {
+ *pFirstSampleInFrameOut = firstSampleInFrame;
+ }
+ if (pLastSampleInFrameOut) {
+ *pLastSampleInFrameOut = lastSampleInFrame;
+ }
+}
+
+static dr_bool32 drflac__seek_to_first_frame(drflac* pFlac)
+{
+ assert(pFlac != NULL);
+
+ dr_bool32 result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos);
+
+ memset(&pFlac->currentFrame, 0, sizeof(pFlac->currentFrame));
+ return result;
+}
+
+static DRFLAC_INLINE dr_bool32 drflac__seek_to_next_frame(drflac* pFlac)
+{
+ // This function should only ever be called while the decoder is sitting on the first byte past the FRAME_HEADER section.
+ assert(pFlac != NULL);
+ return drflac__seek_frame(pFlac);
+}
+
+static dr_bool32 drflac__seek_to_frame_containing_sample(drflac* pFlac, uint64_t sampleIndex)
+{
+ assert(pFlac != NULL);
+
+ if (!drflac__seek_to_first_frame(pFlac)) {
+ return DR_FALSE;
+ }
+
+ uint64_t firstSampleInFrame = 0;
+ uint64_t lastSampleInFrame = 0;
+ for (;;)
+ {
+ // We need to read the frame's header in order to determine the range of samples it contains.
+ if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) {
+ return DR_FALSE;
+ }
+
+ drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame);
+ if (sampleIndex >= firstSampleInFrame && sampleIndex <= lastSampleInFrame) {
+ break; // The sample is in this frame.
+ }
+
+ if (!drflac__seek_to_next_frame(pFlac)) {
+ return DR_FALSE;
+ }
+ }
+
+ // If we get here we should be right at the start of the frame containing the sample.
+ return DR_TRUE;
+}
+
+static dr_bool32 drflac__seek_to_sample__brute_force(drflac* pFlac, uint64_t sampleIndex)
+{
+ if (!drflac__seek_to_frame_containing_sample(pFlac, sampleIndex)) {
+ return DR_FALSE;
+ }
+
+ // At this point we should be sitting on the first byte of the frame containing the sample. We need to decode every sample up to (but
+ // not including) the sample we're seeking to.
+ uint64_t firstSampleInFrame = 0;
+ drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, NULL);
+
+ assert(firstSampleInFrame <= sampleIndex);
+ size_t samplesToDecode = (size_t)(sampleIndex - firstSampleInFrame); // <-- Safe cast because the maximum number of samples in a frame is 65535.
+ if (samplesToDecode == 0) {
+ return DR_TRUE;
+ }
+
+ // At this point we are just sitting on the byte after the frame header. We need to decode the frame before reading anything from it.
+ if (!drflac__decode_frame(pFlac)) {
+ return DR_FALSE;
+ }
+
+ return drflac_read_s32(pFlac, samplesToDecode, NULL) != 0;
+}
+
+
+static dr_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, uint64_t sampleIndex)
+{
+ assert(pFlac != NULL);
+
+ if (pFlac->seektablePos == 0) {
+ return DR_FALSE;
+ }
+
+ if (!drflac__seek_to_byte(&pFlac->bs, pFlac->seektablePos)) {
+ return DR_FALSE;
+ }
+
+ // The number of seek points is derived from the size of the SEEKTABLE block.
+ uint32_t seekpointCount = pFlac->seektableSize / 18; // 18 = the size of each seek point.
+ if (seekpointCount == 0) {
+ return DR_FALSE; // Would this ever happen?
+ }
+
+
+ drflac_seekpoint closestSeekpoint = {0, 0, 0};
+
+ uint32_t seekpointsRemaining = seekpointCount;
+ while (seekpointsRemaining > 0)
+ {
+ drflac_seekpoint seekpoint;
+ if (!drflac__read_uint64(&pFlac->bs, 64, &seekpoint.firstSample)) {
+ break;
+ }
+ if (!drflac__read_uint64(&pFlac->bs, 64, &seekpoint.frameOffset)) {
+ break;
+ }
+ if (!drflac__read_uint16(&pFlac->bs, 16, &seekpoint.sampleCount)) {
+ break;
+ }
+
+ if (seekpoint.firstSample * pFlac->channels > sampleIndex) {
+ break;
+ }
+
+ closestSeekpoint = seekpoint;
+ seekpointsRemaining -= 1;
+ }
+
+ // At this point we should have found the seekpoint closest to our sample. We need to seek to it using basically the same
+ // technique as we use with the brute force method.
+ if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos + closestSeekpoint.frameOffset)) {
+ return DR_FALSE;
+ }
+
+
+ uint64_t firstSampleInFrame = 0;
+ uint64_t lastSampleInFrame = 0;
+ for (;;)
+ {
+ // We need to read the frame's header in order to determine the range of samples it contains.
+ if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) {
+ return DR_FALSE;
+ }
+
+ drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame);
+ if (sampleIndex >= firstSampleInFrame && sampleIndex <= lastSampleInFrame) {
+ break; // The sample is in this frame.
+ }
+
+ if (!drflac__seek_to_next_frame(pFlac)) {
+ return DR_FALSE;
+ }
+ }
+
+ assert(firstSampleInFrame <= sampleIndex);
+
+ // At this point we are just sitting on the byte after the frame header. We need to decode the frame before reading anything from it.
+ if (!drflac__decode_frame(pFlac)) {
+ return DR_FALSE;
+ }
+
+ size_t samplesToDecode = (size_t)(sampleIndex - firstSampleInFrame); // <-- Safe cast because the maximum number of samples in a frame is 65535.
+ return drflac_read_s32(pFlac, samplesToDecode, NULL) == samplesToDecode;
+}
+
+
+#ifndef DR_FLAC_NO_OGG
+typedef struct
+{
+ uint8_t capturePattern[4]; // Should be "OggS"
+ uint8_t structureVersion; // Always 0.
+ uint8_t headerType;
+ uint64_t granulePosition;
+ uint32_t serialNumber;
+ uint32_t sequenceNumber;
+ uint32_t checksum;
+ uint8_t segmentCount;
+ uint8_t segmentTable[255];
+} drflac_ogg_page_header;
+#endif
+
+typedef struct
+{
+ drflac_read_proc onRead;
+ drflac_seek_proc onSeek;
+ drflac_meta_proc onMeta;
+ void* pUserData;
+ void* pUserDataMD;
+ drflac_container container;
+ uint32_t sampleRate;
+ uint8_t channels;
+ uint8_t bitsPerSample;
+ uint64_t totalSampleCount;
+ uint16_t maxBlockSize;
+ uint64_t runningFilePos;
+ dr_bool32 hasMetadataBlocks;
+
+#ifndef DR_FLAC_NO_OGG
+ uint32_t oggSerial;
+ uint64_t oggFirstBytePos;
+ drflac_ogg_page_header oggBosHeader;
+#endif
+} drflac_init_info;
+
+static DRFLAC_INLINE void drflac__decode_block_header(uint32_t blockHeader, uint8_t* isLastBlock, uint8_t* blockType, uint32_t* blockSize)
+{
+ blockHeader = drflac__be2host_32(blockHeader);
+ *isLastBlock = (blockHeader & (0x01 << 31)) >> 31;
+ *blockType = (blockHeader & (0x7F << 24)) >> 24;
+ *blockSize = (blockHeader & 0xFFFFFF);
+}
+
+static DRFLAC_INLINE dr_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, uint8_t* isLastBlock, uint8_t* blockType, uint32_t* blockSize)
+{
+ uint32_t blockHeader;
+ if (onRead(pUserData, &blockHeader, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ drflac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize);
+ return DR_TRUE;
+}
+
+dr_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo)
+{
+ // min/max block size.
+ uint32_t blockSizes;
+ if (onRead(pUserData, &blockSizes, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ // min/max frame size.
+ uint64_t frameSizes = 0;
+ if (onRead(pUserData, &frameSizes, 6) != 6) {
+ return DR_FALSE;
+ }
+
+ // Sample rate, channels, bits per sample and total sample count.
+ uint64_t importantProps;
+ if (onRead(pUserData, &importantProps, 8) != 8) {
+ return DR_FALSE;
+ }
+
+ // MD5
+ uint8_t md5[16];
+ if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) {
+ return DR_FALSE;
+ }
+
+ blockSizes = drflac__be2host_32(blockSizes);
+ frameSizes = drflac__be2host_64(frameSizes);
+ importantProps = drflac__be2host_64(importantProps);
+
+ pStreamInfo->minBlockSize = (blockSizes & 0xFFFF0000) >> 16;
+ pStreamInfo->maxBlockSize = blockSizes & 0x0000FFFF;
+ pStreamInfo->minFrameSize = (uint32_t)((frameSizes & 0xFFFFFF0000000000ULL) >> 40ULL);
+ pStreamInfo->maxFrameSize = (uint32_t)((frameSizes & 0x000000FFFFFF0000ULL) >> 16ULL);
+ pStreamInfo->sampleRate = (uint32_t)((importantProps & 0xFFFFF00000000000ULL) >> 44ULL);
+ pStreamInfo->channels = (uint8_t )((importantProps & 0x00000E0000000000ULL) >> 41ULL) + 1;
+ pStreamInfo->bitsPerSample = (uint8_t )((importantProps & 0x000001F000000000ULL) >> 36ULL) + 1;
+ pStreamInfo->totalSampleCount = (importantProps & 0x0000000FFFFFFFFFULL) * pStreamInfo->channels;
+ memcpy(pStreamInfo->md5, md5, sizeof(md5));
+
+ return DR_TRUE;
+}
+
+dr_bool32 drflac__read_and_decode_metadata(drflac* pFlac)
+{
+ assert(pFlac != NULL);
+
+ // We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that
+ // we'll be sitting on byte 42.
+ uint64_t runningFilePos = 42;
+ uint64_t seektablePos = 0;
+ uint32_t seektableSize = 0;
+
+ for (;;)
+ {
+ uint8_t isLastBlock = 0;
+ uint8_t blockType;
+ uint32_t blockSize;
+ if (!drflac__read_and_decode_block_header(pFlac->bs.onRead, pFlac->bs.pUserData, &isLastBlock, &blockType, &blockSize)) {
+ return DR_FALSE;
+ }
+ runningFilePos += 4;
+
+
+ drflac_metadata metadata;
+ metadata.type = blockType;
+ metadata.pRawData = NULL;
+ metadata.rawDataSize = 0;
+
+ switch (blockType)
+ {
+ case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION:
+ {
+ if (pFlac->onMeta) {
+ void* pRawData = malloc(blockSize);
+ if (pRawData == NULL) {
+ return DR_FALSE;
+ }
+
+ if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) {
+ free(pRawData);
+ return DR_FALSE;
+ }
+
+ metadata.pRawData = pRawData;
+ metadata.rawDataSize = blockSize;
+ metadata.data.application.id = drflac__be2host_32(*(uint32_t*)pRawData);
+ metadata.data.application.pData = (const void*)((uint8_t*)pRawData + sizeof(uint32_t));
+ metadata.data.application.dataSize = blockSize - sizeof(uint32_t);
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+
+ free(pRawData);
+ }
+ } break;
+
+ case DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE:
+ {
+ seektablePos = runningFilePos;
+ seektableSize = blockSize;
+
+ if (pFlac->onMeta) {
+ void* pRawData = malloc(blockSize);
+ if (pRawData == NULL) {
+ return DR_FALSE;
+ }
+
+ if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) {
+ free(pRawData);
+ return DR_FALSE;
+ }
+
+ metadata.pRawData = pRawData;
+ metadata.rawDataSize = blockSize;
+ metadata.data.seektable.seekpointCount = blockSize/sizeof(drflac_seekpoint);
+ metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData;
+
+ // Endian swap.
+ for (uint32_t iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) {
+ drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint;
+ pSeekpoint->firstSample = drflac__be2host_64(pSeekpoint->firstSample);
+ pSeekpoint->frameOffset = drflac__be2host_64(pSeekpoint->frameOffset);
+ pSeekpoint->sampleCount = drflac__be2host_16(pSeekpoint->sampleCount);
+ }
+
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+
+ free(pRawData);
+ }
+ } break;
+
+ case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT:
+ {
+ if (pFlac->onMeta) {
+ void* pRawData = malloc(blockSize);
+ if (pRawData == NULL) {
+ return DR_FALSE;
+ }
+
+ if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) {
+ free(pRawData);
+ return DR_FALSE;
+ }
+
+ metadata.pRawData = pRawData;
+ metadata.rawDataSize = blockSize;
+
+ const char* pRunningData = (const char*)pRawData;
+ metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength;
+ metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.vorbis_comment.comments = pRunningData;
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+
+ free(pRawData);
+ }
+ } break;
+
+ case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET:
+ {
+ if (pFlac->onMeta) {
+ void* pRawData = malloc(blockSize);
+ if (pRawData == NULL) {
+ return DR_FALSE;
+ }
+
+ if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) {
+ free(pRawData);
+ return DR_FALSE;
+ }
+
+ metadata.pRawData = pRawData;
+ metadata.rawDataSize = blockSize;
+
+ const char* pRunningData = (const char*)pRawData;
+ memcpy(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128;
+ metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(uint64_t*)pRunningData); pRunningData += 4;
+ metadata.data.cuesheet.isCD = ((pRunningData[0] & 0x80) >> 7) != 0; pRunningData += 259;
+ metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1;
+ metadata.data.cuesheet.pTrackData = (const uint8_t*)pRunningData;
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+
+ free(pRawData);
+ }
+ } break;
+
+ case DRFLAC_METADATA_BLOCK_TYPE_PICTURE:
+ {
+ if (pFlac->onMeta) {
+ void* pRawData = malloc(blockSize);
+ if (pRawData == NULL) {
+ return DR_FALSE;
+ }
+
+ if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) {
+ free(pRawData);
+ return DR_FALSE;
+ }
+
+ metadata.pRawData = pRawData;
+ metadata.rawDataSize = blockSize;
+
+ const char* pRunningData = (const char*)pRawData;
+ metadata.data.picture.type = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.mimeLength = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength;
+ metadata.data.picture.descriptionLength = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.description = pRunningData;
+ metadata.data.picture.width = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.height = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.colorDepth = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.indexColorCount = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.pictureDataSize = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.pPictureData = (const uint8_t*)pRunningData;
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+
+ free(pRawData);
+ }
+ } break;
+
+ case DRFLAC_METADATA_BLOCK_TYPE_PADDING:
+ {
+ if (pFlac->onMeta) {
+ metadata.data.padding.unused = 0;
+
+ // Padding doesn't have anything meaningful in it, so just skip over it.
+ if (!pFlac->bs.onSeek(pFlac->bs.pUserData, blockSize, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+ }
+ } break;
+
+ case DRFLAC_METADATA_BLOCK_TYPE_INVALID:
+ {
+ // Invalid chunk. Just skip over this one.
+ if (pFlac->onMeta) {
+ if (!pFlac->bs.onSeek(pFlac->bs.pUserData, blockSize, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+ }
+
+ default:
+ {
+ // It's an unknown chunk, but not necessarily invalid. There's a chance more metadata blocks might be defined later on, so we
+ // can at the very least report the chunk to the application and let it look at the raw data.
+ if (pFlac->onMeta) {
+ void* pRawData = malloc(blockSize);
+ if (pRawData == NULL) {
+ return DR_FALSE;
+ }
+
+ if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) {
+ free(pRawData);
+ return DR_FALSE;
+ }
+
+ metadata.pRawData = pRawData;
+ metadata.rawDataSize = blockSize;
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+
+ free(pRawData);
+ }
+ } break;
+ }
+
+ // If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above.
+ if (pFlac->onMeta == NULL) {
+ if (!pFlac->bs.onSeek(pFlac->bs.pUserData, blockSize, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+
+ runningFilePos += blockSize;
+ if (isLastBlock) {
+ break;
+ }
+ }
+
+ pFlac->seektablePos = seektablePos;
+ pFlac->seektableSize = seektableSize;
+ pFlac->firstFramePos = runningFilePos;
+
+ return DR_TRUE;
+}
+
+dr_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+{
+ (void)onSeek;
+
+ // Pre: The bit stream should be sitting just past the 4-byte id header.
+
+ pInit->container = drflac_container_native;
+
+ // The first metadata block should be the STREAMINFO block.
+ uint8_t isLastBlock;
+ uint8_t blockType;
+ uint32_t blockSize;
+ if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
+ return DR_FALSE;
+ }
+
+ if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
+ return DR_FALSE; // Invalid block type. First block must be the STREAMINFO block.
+ }
+
+
+ drflac_streaminfo streaminfo;
+ if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) {
+ return DR_FALSE;
+ }
+
+ pInit->sampleRate = streaminfo.sampleRate;
+ pInit->channels = streaminfo.channels;
+ pInit->bitsPerSample = streaminfo.bitsPerSample;
+ pInit->totalSampleCount = streaminfo.totalSampleCount;
+ pInit->maxBlockSize = streaminfo.maxBlockSize; // Don't care about the min block size - only the max (used for determining the size of the memory allocation).
+
+ if (onMeta) {
+ drflac_metadata metadata;
+ metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
+ metadata.pRawData = NULL;
+ metadata.rawDataSize = 0;
+ metadata.data.streaminfo = streaminfo;
+ onMeta(pUserDataMD, &metadata);
+ }
+
+ pInit->hasMetadataBlocks = !isLastBlock;
+ return DR_TRUE;
+}
+
+#ifndef DR_FLAC_NO_OGG
+static DRFLAC_INLINE dr_bool32 drflac_ogg__is_capture_pattern(uint8_t pattern[4])
+{
+ return pattern[0] == 'O' && pattern[1] == 'g' && pattern[2] == 'g' && pattern[3] == 'S';
+}
+
+static DRFLAC_INLINE uint32_t drflac_ogg__get_page_header_size(drflac_ogg_page_header* pHeader)
+{
+ return 27 + pHeader->segmentCount;
+}
+
+static DRFLAC_INLINE uint32_t drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader)
+{
+ uint32_t pageBodySize = 0;
+ for (int i = 0; i < pHeader->segmentCount; ++i) {
+ pageBodySize += pHeader->segmentTable[i];
+ }
+
+ return pageBodySize;
+}
+
+dr_bool32 drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize)
+{
+ if (onRead(pUserData, &pHeader->structureVersion, 1) != 1 || pHeader->structureVersion != 0) {
+ return DR_FALSE; // Unknown structure version. Possibly corrupt stream.
+ }
+ if (onRead(pUserData, &pHeader->headerType, 1) != 1) {
+ return DR_FALSE;
+ }
+ if (onRead(pUserData, &pHeader->granulePosition, 8) != 8) {
+ return DR_FALSE;
+ }
+ if (onRead(pUserData, &pHeader->serialNumber, 4) != 4) {
+ return DR_FALSE;
+ }
+ if (onRead(pUserData, &pHeader->sequenceNumber, 4) != 4) {
+ return DR_FALSE;
+ }
+ if (onRead(pUserData, &pHeader->checksum, 4) != 4) {
+ return DR_FALSE;
+ }
+ if (onRead(pUserData, &pHeader->segmentCount, 1) != 1 || pHeader->segmentCount == 0) {
+ return DR_FALSE; // Should not have a segment count of 0.
+ }
+ if (onRead(pUserData, &pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) {
+ return DR_FALSE;
+ }
+
+ if (pHeaderSize) *pHeaderSize = (27 + pHeader->segmentCount);
+ return DR_TRUE;
+}
+
+dr_bool32 drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize)
+{
+ uint8_t id[4];
+ if (onRead(pUserData, id, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ if (id[0] != 'O' || id[1] != 'g' || id[2] != 'g' || id[3] != 'S') {
+ return DR_FALSE;
+ }
+
+ return drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pHeaderSize);
+}
+
+
+// The main part of the Ogg encapsulation is the conversion from the physical Ogg bitstream to the native FLAC bitstream. It works
+// in three general stages: Ogg Physical Bitstream -> Ogg/FLAC Logical Bitstream -> FLAC Native Bitstream. dr_flac is architecured
+// in such a way that the core sections assume everything is delivered in native format. Therefore, for each encapsulation type
+// dr_flac is supporting there needs to be a layer sitting on top of the onRead and onSeek callbacks that ensures the bits read from
+// the physical Ogg bitstream are converted and delivered in native FLAC format.
+typedef struct
+{
+ drflac_read_proc onRead; // The original onRead callback from drflac_open() and family.
+ drflac_seek_proc onSeek; // The original onSeek callback from drflac_open() and family.
+ void* pUserData; // The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family.
+ uint64_t currentBytePos; // The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking.
+ uint64_t firstBytePos; // The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page.
+ uint32_t serialNumber; // The serial number of the FLAC audio pages. This is determined by the initial header page that was read during initialization.
+ drflac_ogg_page_header bosPageHeader; // Used for seeking.
+ drflac_ogg_page_header currentPageHeader;
+ uint32_t bytesRemainingInPage;
+} drflac_oggbs; // oggbs = Ogg Bitstream
+
+static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, size_t bytesToRead)
+{
+ size_t bytesActuallyRead = oggbs->onRead(oggbs->pUserData, bufferOut, bytesToRead);
+ oggbs->currentBytePos += bytesActuallyRead;
+
+ return bytesActuallyRead;
+}
+
+static dr_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, uint64_t offset, drflac_seek_origin origin)
+{
+ if (origin == drflac_seek_origin_start)
+ {
+ if (offset <= 0x7FFFFFFF) {
+ if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_start)) {
+ return DR_FALSE;
+ }
+ oggbs->currentBytePos = offset;
+
+ return DR_TRUE;
+ } else {
+ if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
+ return DR_FALSE;
+ }
+ oggbs->currentBytePos = offset;
+
+ return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, drflac_seek_origin_current);
+ }
+ }
+ else
+ {
+ while (offset > 0x7FFFFFFF) {
+ if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ oggbs->currentBytePos += 0x7FFFFFFF;
+ offset -= 0x7FFFFFFF;
+ }
+
+ if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { // <-- Safe cast thanks to the loop above.
+ return DR_FALSE;
+ }
+ oggbs->currentBytePos += offset;
+
+ return DR_TRUE;
+ }
+}
+
+static dr_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs)
+{
+ drflac_ogg_page_header header;
+ for (;;)
+ {
+ uint32_t headerSize;
+ if (!drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &headerSize)) {
+ return DR_FALSE;
+ }
+ oggbs->currentBytePos += headerSize;
+
+
+ uint32_t pageBodySize = drflac_ogg__get_page_body_size(&header);
+
+ if (header.serialNumber == oggbs->serialNumber) {
+ oggbs->currentPageHeader = header;
+ oggbs->bytesRemainingInPage = pageBodySize;
+ return DR_TRUE;
+ }
+
+ // If we get here it means the page is not a FLAC page - skip it.
+ if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) { // <-- Safe cast - maximum size of a page is way below that of an int.
+ return DR_FALSE;
+ }
+ }
+}
+
+// Function below is unused at the moment, but I might be re-adding it later.
+#if 0
+static uint8_t drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, uint8_t* pBytesRemainingInSeg)
+{
+ uint32_t bytesConsumedInPage = drflac_ogg__get_page_body_size(&oggbs->currentPageHeader) - oggbs->bytesRemainingInPage;
+ uint8_t iSeg = 0;
+ uint32_t iByte = 0;
+ while (iByte < bytesConsumedInPage)
+ {
+ uint8_t segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
+ if (iByte + segmentSize > bytesConsumedInPage) {
+ break;
+ } else {
+ iSeg += 1;
+ iByte += segmentSize;
+ }
+ }
+
+ *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (uint8_t)(bytesConsumedInPage - iByte);
+ return iSeg;
+}
+
+static dr_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
+{
+ // The current packet ends when we get to the segment with a lacing value of < 255 which is not at the end of a page.
+ for (;;) // <-- Loop over pages.
+ {
+ dr_bool32 atEndOfPage = DR_FALSE;
+
+ uint8_t bytesRemainingInSeg;
+ uint8_t iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg);
+
+ uint32_t bytesToEndOfPacketOrPage = bytesRemainingInSeg;
+ for (uint8_t iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) {
+ uint8_t segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
+ if (segmentSize < 255) {
+ if (iSeg == oggbs->currentPageHeader.segmentCount-1) {
+ atEndOfPage = DR_TRUE;
+ }
+
+ break;
+ }
+
+ bytesToEndOfPacketOrPage += segmentSize;
+ }
+
+ // At this point we will have found either the packet or the end of the page. If were at the end of the page we'll
+ // want to load the next page and keep searching for the end of the frame.
+ drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current);
+ oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage;
+
+ if (atEndOfPage)
+ {
+ // We're potentially at the next packet, but we need to check the next page first to be sure because the packet may
+ // straddle pages.
+ if (!drflac_oggbs__goto_next_page(oggbs)) {
+ return DR_FALSE;
+ }
+
+ // If it's a fresh packet it most likely means we're at the next packet.
+ if ((oggbs->currentPageHeader.headerType & 0x01) == 0) {
+ return DR_TRUE;
+ }
+ }
+ else
+ {
+ // We're at the next frame.
+ return DR_TRUE;
+ }
+ }
+}
+
+static dr_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs)
+{
+ // The bitstream should be sitting on the first byte just after the header of the frame.
+
+ // What we're actually doing here is seeking to the start of the next packet.
+ return drflac_oggbs__seek_to_next_packet(oggbs);
+}
+#endif
+
+static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead)
+{
+ drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
+ assert(oggbs != NULL);
+
+ uint8_t* pRunningBufferOut = (uint8_t*)bufferOut;
+
+ // Reading is done page-by-page. If we've run out of bytes in the page we need to move to the next one.
+ size_t bytesRead = 0;
+ while (bytesRead < bytesToRead)
+ {
+ size_t bytesRemainingToRead = bytesToRead - bytesRead;
+
+ if (oggbs->bytesRemainingInPage >= bytesRemainingToRead) {
+ bytesRead += oggbs->onRead(oggbs->pUserData, pRunningBufferOut, bytesRemainingToRead);
+ oggbs->bytesRemainingInPage -= (uint32_t)bytesRemainingToRead;
+ break;
+ }
+
+ // If we get here it means some of the requested data is contained in the next pages.
+ if (oggbs->bytesRemainingInPage > 0) {
+ size_t bytesJustRead = oggbs->onRead(oggbs->pUserData, pRunningBufferOut, oggbs->bytesRemainingInPage);
+ bytesRead += bytesJustRead;
+ pRunningBufferOut += bytesJustRead;
+
+ if (bytesJustRead != oggbs->bytesRemainingInPage) {
+ break; // Ran out of data.
+ }
+ }
+
+ assert(bytesRemainingToRead > 0);
+ if (!drflac_oggbs__goto_next_page(oggbs)) {
+ break; // Failed to go to the next chunk. Might have simply hit the end of the stream.
+ }
+ }
+
+ oggbs->currentBytePos += bytesRead;
+ return bytesRead;
+}
+
+static dr_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin)
+{
+ drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
+ assert(oggbs != NULL);
+ assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start));
+
+ // Seeking is always forward which makes things a lot simpler.
+ if (origin == drflac_seek_origin_start) {
+ int startBytePos = (int)oggbs->firstBytePos + (79-42); // 79 = size of bos page; 42 = size of FLAC header data. Seek up to the first byte of the native FLAC data.
+ if (!drflac_oggbs__seek_physical(oggbs, startBytePos, drflac_seek_origin_start)) {
+ return DR_FALSE;
+ }
+
+ oggbs->currentPageHeader = oggbs->bosPageHeader;
+ oggbs->bytesRemainingInPage = 42; // 42 = size of the native FLAC header data. That's our start point for seeking.
+
+ return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current);
+ }
+
+
+ assert(origin == drflac_seek_origin_current);
+
+ int bytesSeeked = 0;
+ while (bytesSeeked < offset)
+ {
+ int bytesRemainingToSeek = offset - bytesSeeked;
+ assert(bytesRemainingToSeek >= 0);
+
+ if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) {
+ if (!drflac_oggbs__seek_physical(oggbs, bytesRemainingToSeek, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+
+ bytesSeeked += bytesRemainingToSeek;
+ oggbs->bytesRemainingInPage -= bytesRemainingToSeek;
+ break;
+ }
+
+ // If we get here it means some of the requested data is contained in the next pages.
+ if (oggbs->bytesRemainingInPage > 0) {
+ if (!drflac_oggbs__seek_physical(oggbs, oggbs->bytesRemainingInPage, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+
+ bytesSeeked += (int)oggbs->bytesRemainingInPage;
+ }
+
+ assert(bytesRemainingToSeek > 0);
+ if (!drflac_oggbs__goto_next_page(oggbs)) {
+ break; // Failed to go to the next chunk. Might have simply hit the end of the stream.
+ }
+ }
+
+ return DR_TRUE;
+}
+
+dr_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, uint64_t sample)
+{
+ drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + pFlac->maxBlockSize*pFlac->channels);
+
+ uint64_t originalBytePos = oggbs->currentBytePos; // For recovery.
+
+ // First seek to the first frame.
+ if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos)) {
+ return DR_FALSE;
+ }
+ oggbs->bytesRemainingInPage = 0;
+
+ uint64_t runningGranulePosition = 0;
+ uint64_t runningFrameBytePos = oggbs->currentBytePos; // <-- Points to the OggS identifier.
+ for (;;)
+ {
+ if (!drflac_oggbs__goto_next_page(oggbs)) {
+ drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
+ return DR_FALSE; // Never did find that sample...
+ }
+
+ runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader);
+ if (oggbs->currentPageHeader.granulePosition*pFlac->channels >= sample) {
+ break; // The sample is somewhere in the previous page.
+ }
+
+
+ // At this point we know the sample is not in the previous page. It could possibly be in this page. For simplicity we
+ // disregard any pages that do not begin a fresh packet.
+ if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { // <-- Is it a fresh page?
+ if (oggbs->currentPageHeader.segmentTable[0] >= 2) {
+ uint8_t firstBytesInPage[2];
+ if (drflac_oggbs__read_physical(oggbs, firstBytesInPage, 2) != 2) {
+ drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
+ return DR_FALSE;
+ }
+ if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) { // <-- Does the page begin with a frame's sync code?
+ runningGranulePosition = oggbs->currentPageHeader.granulePosition*pFlac->channels;
+ }
+
+ if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->bytesRemainingInPage-2, drflac_seek_origin_current)) {
+ drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
+ return DR_FALSE;
+ }
+
+ continue;
+ }
+ }
+
+ if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->bytesRemainingInPage, drflac_seek_origin_current)) {
+ drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
+ return DR_FALSE;
+ }
+ }
+
+
+ // We found the page that that is closest to the sample, so now we need to find it. The first thing to do is seek to the
+ // start of that page. In the loop above we checked that it was a fresh page which means this page is also the start of
+ // a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until
+ // we find the one containing the target sample.
+ if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) {
+ return DR_FALSE;
+ }
+ if (!drflac_oggbs__goto_next_page(oggbs)) {
+ return DR_FALSE;
+ }
+
+
+ // At this point we'll be sitting on the first byte of the frame header of the first frame in the page. We just keep
+ // looping over these frames until we find the one containing the sample we're after.
+ uint64_t firstSampleInFrame = runningGranulePosition;
+ for (;;)
+ {
+ // NOTE for later: When using Ogg's page/segment based seeking later on we can't use this function (or any drflac__*
+ // reading functions) because otherwise it will pull extra data for use in it's own internal caches which will then
+ // break the positioning of the read pointer for the Ogg bitstream.
+ if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) {
+ return DR_FALSE;
+ }
+
+ int channels = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
+ uint64_t lastSampleInFrame = firstSampleInFrame + (pFlac->currentFrame.header.blockSize*channels);
+ lastSampleInFrame -= 1; // <-- Zero based.
+
+ if (sample >= firstSampleInFrame && sample <= lastSampleInFrame) {
+ break; // The sample is in this frame.
+ }
+
+
+ // If we get here it means the sample is not in this frame so we need to move to the next one. Now the cool thing
+ // with Ogg is that we can efficiently seek past the frame by looking at the lacing values of each segment in
+ // the page.
+ firstSampleInFrame = lastSampleInFrame+1;
+
+#if 1
+ // Slow way. This uses the native FLAC decoder to seek past the frame. This is slow because it needs to do a partial
+ // decode of the frame. Although this is how the native version works, we can use Ogg's framing system to make it
+ // more efficient. Leaving this here for reference and to use as a basis for debugging purposes.
+ if (!drflac__seek_to_next_frame(pFlac)) {
+ return DR_FALSE;
+ }
+#else
+ // TODO: This is not yet complete. See note at the top of this loop body.
+
+ // Fast(er) way. This uses Ogg's framing system to seek past the frame. This should be much more efficient than the
+ // native FLAC seeking.
+ if (!drflac_oggbs__seek_to_next_frame(oggbs)) {
+ return DR_FALSE;
+ }
+#endif
+ }
+
+ assert(firstSampleInFrame <= sample);
+
+ if (!drflac__decode_frame(pFlac)) {
+ return DR_FALSE;
+ }
+
+ size_t samplesToDecode = (size_t)(sample - firstSampleInFrame); // <-- Safe cast because the maximum number of samples in a frame is 65535.
+ return drflac_read_s32(pFlac, samplesToDecode, NULL) == samplesToDecode;
+}
+
+
+dr_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+{
+ // Pre: The bit stream should be sitting just past the 4-byte OggS capture pattern.
+
+ pInit->container = drflac_container_ogg;
+ pInit->oggFirstBytePos = 0;
+
+ // We'll get here if the first 4 bytes of the stream were the OggS capture pattern, however it doesn't necessarily mean the
+ // stream includes FLAC encoded audio. To check for this we need to scan the beginning-of-stream page markers and check if
+ // any match the FLAC specification. Important to keep in mind that the stream may be multiplexed.
+ drflac_ogg_page_header header;
+
+ uint32_t headerSize;
+ if (!drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &headerSize)) {
+ return DR_FALSE;
+ }
+ pInit->runningFilePos = headerSize;
+
+ for (;;)
+ {
+ // Break if we're past the beginning of stream page.
+ if ((header.headerType & 0x02) == 0) {
+ return DR_FALSE;
+ }
+
+
+ // Check if it's a FLAC header.
+ int pageBodySize = drflac_ogg__get_page_body_size(&header);
+ if (pageBodySize == 51) // 51 = the lacing value of the FLAC header packet.
+ {
+ // It could be a FLAC page...
+ uint32_t bytesRemainingInPage = pageBodySize;
+
+ uint8_t packetType;
+ if (onRead(pUserData, &packetType, 1) != 1) {
+ return DR_FALSE;
+ }
+
+ bytesRemainingInPage -= 1;
+ if (packetType == 0x7F)
+ {
+ // Increasingly more likely to be a FLAC page...
+ uint8_t sig[4];
+ if (onRead(pUserData, sig, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ bytesRemainingInPage -= 4;
+ if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C')
+ {
+ // Almost certainly a FLAC page...
+ uint8_t mappingVersion[2];
+ if (onRead(pUserData, mappingVersion, 2) != 2) {
+ return DR_FALSE;
+ }
+
+ if (mappingVersion[0] != 1) {
+ return DR_FALSE; // Only supporting version 1.x of the Ogg mapping.
+ }
+
+ // The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to
+ // be handling it in a generic way based on the serial number and packet types.
+ if (!onSeek(pUserData, 2, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+
+ // Expecting the native FLAC signature "fLaC".
+ if (onRead(pUserData, sig, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C')
+ {
+ // The remaining data in the page should be the STREAMINFO block.
+ uint8_t isLastBlock;
+ uint8_t blockType;
+ uint32_t blockSize;
+ if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
+ return DR_FALSE;
+ }
+
+ if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
+ return DR_FALSE; // Invalid block type. First block must be the STREAMINFO block.
+ }
+
+ drflac_streaminfo streaminfo;
+ if (drflac__read_streaminfo(onRead, pUserData, &streaminfo))
+ {
+ // Success!
+ pInit->sampleRate = streaminfo.sampleRate;
+ pInit->channels = streaminfo.channels;
+ pInit->bitsPerSample = streaminfo.bitsPerSample;
+ pInit->totalSampleCount = streaminfo.totalSampleCount;
+ pInit->maxBlockSize = streaminfo.maxBlockSize;
+
+ if (onMeta) {
+ drflac_metadata metadata;
+ metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
+ metadata.pRawData = NULL;
+ metadata.rawDataSize = 0;
+ metadata.data.streaminfo = streaminfo;
+ onMeta(pUserDataMD, &metadata);
+ }
+
+ pInit->runningFilePos += pageBodySize;
+ pInit->oggFirstBytePos = pInit->runningFilePos - 79; // Subtracting 79 will place us right on top of the "OggS" identifier of the FLAC bos page.
+ pInit->oggSerial = header.serialNumber;
+ pInit->oggBosHeader = header;
+ break;
+ }
+ else
+ {
+ // Failed to read STREAMINFO block. Aww, so close...
+ return DR_FALSE;
+ }
+ }
+ else
+ {
+ // Invalid file.
+ return DR_FALSE;
+ }
+ }
+ else
+ {
+ // Not a FLAC header. Skip it.
+ if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+ }
+ else
+ {
+ // Not a FLAC header. Seek past the entire page and move on to the next.
+ if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+ }
+ else
+ {
+ if (!onSeek(pUserData, pageBodySize, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+
+ pInit->runningFilePos += pageBodySize;
+
+
+ // Read the header of the next page.
+ if (!drflac_ogg__read_page_header(onRead, pUserData, &header, &headerSize)) {
+ return DR_FALSE;
+ }
+ pInit->runningFilePos += headerSize;
+ }
+
+
+ // If we get here it means we found a FLAC audio stream. We should be sitting on the first byte of the header of the next page. The next
+ // packets in the FLAC logical stream contain the metadata. The only thing left to do in the initialiation phase for Ogg is to create the
+ // Ogg bistream object.
+ pInit->hasMetadataBlocks = DR_TRUE; // <-- Always have at least VORBIS_COMMENT metadata block.
+ return DR_TRUE;
+}
+#endif
+
+dr_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+{
+ if (pInit == NULL || onRead == NULL || onSeek == NULL) {
+ return DR_FALSE;
+ }
+
+ pInit->onRead = onRead;
+ pInit->onSeek = onSeek;
+ pInit->onMeta = onMeta;
+ pInit->pUserData = pUserData;
+ pInit->pUserDataMD = pUserDataMD;
+
+ uint8_t id[4];
+ if (onRead(pUserData, id, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ if (id[0] == 'f' && id[1] == 'L' && id[2] == 'a' && id[3] == 'C') {
+ return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD);
+ }
+
+#ifndef DR_FLAC_NO_OGG
+ if (id[0] == 'O' && id[1] == 'g' && id[2] == 'g' && id[3] == 'S') {
+ return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD);
+ }
+#endif
+
+ // Unsupported container.
+ return DR_FALSE;
+}
+
+void drflac__init_from_info(drflac* pFlac, drflac_init_info* pInit)
+{
+ assert(pFlac != NULL);
+ assert(pInit != NULL);
+
+ memset(pFlac, 0, sizeof(*pFlac));
+ pFlac->bs.onRead = pInit->onRead;
+ pFlac->bs.onSeek = pInit->onSeek;
+ pFlac->bs.pUserData = pInit->pUserData;
+ pFlac->bs.nextL2Line = sizeof(pFlac->bs.cacheL2) / sizeof(pFlac->bs.cacheL2[0]); // <-- Initialize to this to force a client-side data retrieval right from the start.
+ pFlac->bs.consumedBits = sizeof(pFlac->bs.cache)*8;
+
+ pFlac->onMeta = pInit->onMeta;
+ pFlac->pUserDataMD = pInit->pUserDataMD;
+ pFlac->maxBlockSize = pInit->maxBlockSize;
+ pFlac->sampleRate = pInit->sampleRate;
+ pFlac->channels = (uint8_t)pInit->channels;
+ pFlac->bitsPerSample = (uint8_t)pInit->bitsPerSample;
+ pFlac->totalSampleCount = pInit->totalSampleCount;
+ pFlac->container = pInit->container;
+}
+
+drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+{
+ drflac_init_info init;
+ if (!drflac__init_private(&init, onRead, onSeek, onMeta, pUserData, pUserDataMD)) {
+ return NULL;
+ }
+
+ size_t allocationSize = sizeof(drflac);
+ allocationSize += init.maxBlockSize * init.channels * sizeof(int32_t);
+ //allocationSize += init.seektableSize;
+
+
+#ifndef DR_FLAC_NO_OGG
+ // There's additional data required for Ogg streams.
+ if (init.container == drflac_container_ogg) {
+ allocationSize += sizeof(drflac_oggbs);
+ }
+#endif
+
+ drflac* pFlac = (drflac*)malloc(allocationSize);
+ drflac__init_from_info(pFlac, &init);
+ pFlac->pDecodedSamples = (int32_t*)pFlac->pExtraData;
+
+#ifndef DR_FLAC_NO_OGG
+ if (init.container == drflac_container_ogg) {
+ drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + init.maxBlockSize*init.channels);
+ oggbs->onRead = onRead;
+ oggbs->onSeek = onSeek;
+ oggbs->pUserData = pUserData;
+ oggbs->currentBytePos = init.oggFirstBytePos;
+ oggbs->firstBytePos = init.oggFirstBytePos;
+ oggbs->serialNumber = init.oggSerial;
+ oggbs->bosPageHeader = init.oggBosHeader;
+ oggbs->bytesRemainingInPage = 0;
+
+ // The Ogg bistream needs to be layered on top of the original bitstream.
+ pFlac->bs.onRead = drflac__on_read_ogg;
+ pFlac->bs.onSeek = drflac__on_seek_ogg;
+ pFlac->bs.pUserData = (void*)oggbs;
+ }
+#endif
+
+ // Decode metadata before returning.
+ if (init.hasMetadataBlocks) {
+ if (!drflac__read_and_decode_metadata(pFlac)) {
+ free(pFlac);
+ return NULL;
+ }
+ }
+
+ return pFlac;
+}
+
+
+
+#ifndef DR_FLAC_NO_STDIO
+typedef void* drflac_file;
+
+#if defined(DR_FLAC_NO_WIN32_IO) || !defined(_WIN32)
+#include <stdio.h>
+
+static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
+{
+ return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
+}
+
+static dr_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
+{
+ assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start));
+
+ return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
+}
+
+static drflac_file drflac__open_file_handle(const char* filename)
+{
+ FILE* pFile;
+#ifdef _MSC_VER
+ if (fopen_s(&pFile, filename, "rb") != 0) {
+ return NULL;
+ }
+#else
+ pFile = fopen(filename, "rb");
+ if (pFile == NULL) {
+ return NULL;
+ }
+#endif
+
+ return (drflac_file)pFile;
+}
+
+static void drflac__close_file_handle(drflac_file file)
+{
+ fclose((FILE*)file);
+}
+#else
+#include <windows.h>
+
+static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
+{
+ assert(bytesToRead < 0xFFFFFFFF); // dr_flac will never request huge amounts of data at a time. This is a safe assertion.
+
+ DWORD bytesRead;
+ ReadFile((HANDLE)pUserData, bufferOut, (DWORD)bytesToRead, &bytesRead, NULL);
+
+ return (size_t)bytesRead;
+}
+
+static dr_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
+{
+ assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start));
+
+ return SetFilePointer((HANDLE)pUserData, offset, NULL, (origin == drflac_seek_origin_current) ? FILE_CURRENT : FILE_BEGIN) != INVALID_SET_FILE_POINTER;
+}
+
+static drflac_file drflac__open_file_handle(const char* filename)
+{
+ HANDLE hFile = CreateFileA(filename, FILE_GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ return NULL;
+ }
+
+ return (drflac_file)hFile;
+}
+
+static void drflac__close_file_handle(drflac_file file)
+{
+ CloseHandle((HANDLE)file);
+}
+#endif
+
+
+drflac* drflac_open_file(const char* filename)
+{
+ drflac_file file = drflac__open_file_handle(filename);
+ if (file == NULL) {
+ return NULL;
+ }
+
+ drflac* pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)file);
+ if (pFlac == NULL) {
+ drflac__close_file_handle(file);
+ return NULL;
+ }
+
+ return pFlac;
+}
+
+drflac* drflac_open_file_with_metadata(const char* filename, drflac_meta_proc onMeta, void* pUserData)
+{
+ drflac_file file = drflac__open_file_handle(filename);
+ if (file == NULL) {
+ return NULL;
+ }
+
+ drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, (void*)file, pUserData);
+ if (pFlac == NULL) {
+ drflac__close_file_handle(file);
+ return pFlac;
+ }
+
+ return pFlac;
+}
+#endif //DR_FLAC_NO_STDIO
+
+static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead)
+{
+ drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
+ assert(memoryStream != NULL);
+ assert(memoryStream->dataSize >= memoryStream->currentReadPos);
+
+ size_t bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos;
+ if (bytesToRead > bytesRemaining) {
+ bytesToRead = bytesRemaining;
+ }
+
+ if (bytesToRead > 0) {
+ memcpy(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead);
+ memoryStream->currentReadPos += bytesToRead;
+ }
+
+ return bytesToRead;
+}
+
+static dr_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
+{
+ drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
+ assert(memoryStream != NULL);
+ assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start));
+
+ if (origin == drflac_seek_origin_current) {
+ if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) {
+ memoryStream->currentReadPos += offset;
+ } else {
+ memoryStream->currentReadPos = memoryStream->dataSize; // Trying to seek too far forward.
+ }
+ } else {
+ if ((uint32_t)offset <= memoryStream->dataSize) {
+ memoryStream->currentReadPos = offset;
+ } else {
+ memoryStream->currentReadPos = memoryStream->dataSize; // Trying to seek too far forward.
+ }
+ }
+
+ return DR_TRUE;
+}
+
+drflac* drflac_open_memory(const void* data, size_t dataSize)
+{
+ drflac__memory_stream memoryStream;
+ memoryStream.data = (const unsigned char*)data;
+ memoryStream.dataSize = dataSize;
+ memoryStream.currentReadPos = 0;
+ drflac* pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ pFlac->memoryStream = memoryStream;
+
+ // This is an awful hack...
+#ifndef DR_FLAC_NO_OGG
+ if (pFlac->container == drflac_container_ogg)
+ {
+ drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + pFlac->maxBlockSize*pFlac->channels);
+ oggbs->pUserData = &pFlac->memoryStream;
+ }
+ else
+#endif
+ {
+ pFlac->bs.pUserData = &pFlac->memoryStream;
+ }
+
+ return pFlac;
+}
+
+drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drflac_meta_proc onMeta, void* pUserData)
+{
+ drflac__memory_stream memoryStream;
+ memoryStream.data = (const unsigned char*)data;
+ memoryStream.dataSize = dataSize;
+ memoryStream.currentReadPos = 0;
+ drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, &memoryStream, pUserData);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ pFlac->memoryStream = memoryStream;
+
+ // This is an awful hack...
+#ifndef DR_FLAC_NO_OGG
+ if (pFlac->container == drflac_container_ogg)
+ {
+ drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + pFlac->maxBlockSize*pFlac->channels);
+ oggbs->pUserData = &pFlac->memoryStream;
+ }
+ else
+#endif
+ {
+ pFlac->bs.pUserData = &pFlac->memoryStream;
+ }
+
+ return pFlac;
+}
+
+
+
+drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData)
+{
+ return drflac_open_with_metadata_private(onRead, onSeek, NULL, pUserData, pUserData);
+}
+
+drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData)
+{
+ return drflac_open_with_metadata_private(onRead, onSeek, onMeta, pUserData, pUserData);
+}
+
+void drflac_close(drflac* pFlac)
+{
+ if (pFlac == NULL) {
+ return;
+ }
+
+#ifndef DR_FLAC_NO_STDIO
+ // If we opened the file with drflac_open_file() we will want to close the file handle. We can know whether or not drflac_open_file()
+ // was used by looking at the callbacks.
+ if (pFlac->bs.onRead == drflac__on_read_stdio) {
+ drflac__close_file_handle((drflac_file)pFlac->bs.pUserData);
+ }
+
+#ifndef DR_FLAC_NO_OGG
+ // Need to clean up Ogg streams a bit differently due to the way the bit streaming is chained.
+ if (pFlac->container == drflac_container_ogg) {
+ assert(pFlac->bs.onRead == drflac__on_read_ogg);
+ drflac_oggbs* oggbs = (drflac_oggbs*)((int32_t*)pFlac->pExtraData + pFlac->maxBlockSize*pFlac->channels);
+ if (oggbs->onRead == drflac__on_read_stdio) {
+ drflac__close_file_handle((drflac_file)oggbs->pUserData);
+ }
+ }
+#endif
+#endif
+
+ free(pFlac);
+}
+
+uint64_t drflac__read_s32__misaligned(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferOut)
+{
+ unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
+
+ // We should never be calling this when the number of samples to read is >= the sample count.
+ assert(samplesToRead < channelCount);
+ assert(pFlac->currentFrame.samplesRemaining > 0 && samplesToRead <= pFlac->currentFrame.samplesRemaining);
+
+
+ uint64_t samplesRead = 0;
+ while (samplesToRead > 0)
+ {
+ uint64_t totalSamplesInFrame = pFlac->currentFrame.header.blockSize * channelCount;
+ uint64_t samplesReadFromFrameSoFar = totalSamplesInFrame - pFlac->currentFrame.samplesRemaining;
+ unsigned int channelIndex = samplesReadFromFrameSoFar % channelCount;
+
+ uint64_t nextSampleInFrame = samplesReadFromFrameSoFar / channelCount;
+
+ int decodedSample = 0;
+ switch (pFlac->currentFrame.header.channelAssignment)
+ {
+ case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ {
+ if (channelIndex == 0) {
+ decodedSample = pFlac->currentFrame.subframes[channelIndex].pDecodedSamples[nextSampleInFrame];
+ } else {
+ int side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame];
+ int left = pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame];
+ decodedSample = left - side;
+ }
+
+ } break;
+
+ case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ {
+ if (channelIndex == 0) {
+ int side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame];
+ int right = pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame];
+ decodedSample = side + right;
+ } else {
+ decodedSample = pFlac->currentFrame.subframes[channelIndex].pDecodedSamples[nextSampleInFrame];
+ }
+
+ } break;
+
+ case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
+ {
+ int mid;
+ int side;
+ if (channelIndex == 0) {
+ mid = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame];
+ side = pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame];
+
+ mid = (((unsigned int)mid) << 1) | (side & 0x01);
+ decodedSample = (mid + side) >> 1;
+ } else {
+ mid = pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame];
+ side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame];
+
+ mid = (((unsigned int)mid) << 1) | (side & 0x01);
+ decodedSample = (mid - side) >> 1;
+ }
+
+ } break;
+
+ case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
+ default:
+ {
+ decodedSample = pFlac->currentFrame.subframes[channelIndex].pDecodedSamples[nextSampleInFrame];
+ } break;
+ }
+
+
+ decodedSample <<= ((32 - pFlac->bitsPerSample) + pFlac->currentFrame.subframes[channelIndex].wastedBitsPerSample);
+
+ if (bufferOut) {
+ *bufferOut++ = decodedSample;
+ }
+
+ samplesRead += 1;
+ pFlac->currentFrame.samplesRemaining -= 1;
+ samplesToRead -= 1;
+ }
+
+ return samplesRead;
+}
+
+uint64_t drflac__seek_forward_by_samples(drflac* pFlac, uint64_t samplesToRead)
+{
+ uint64_t samplesRead = 0;
+ while (samplesToRead > 0)
+ {
+ if (pFlac->currentFrame.samplesRemaining == 0)
+ {
+ if (!drflac__read_and_decode_next_frame(pFlac)) {
+ break; // Couldn't read the next frame, so just break from the loop and return.
+ }
+ }
+ else
+ {
+ samplesRead += 1;
+ pFlac->currentFrame.samplesRemaining -= 1;
+ samplesToRead -= 1;
+ }
+ }
+
+ return samplesRead;
+}
+
+uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferOut)
+{
+ // Note that <bufferOut> is allowed to be null, in which case this will be treated as something like a seek.
+ if (pFlac == NULL || samplesToRead == 0) {
+ return 0;
+ }
+
+ if (bufferOut == NULL) {
+ return drflac__seek_forward_by_samples(pFlac, samplesToRead);
+ }
+
+
+ uint64_t samplesRead = 0;
+ while (samplesToRead > 0)
+ {
+ // If we've run out of samples in this frame, go to the next.
+ if (pFlac->currentFrame.samplesRemaining == 0)
+ {
+ if (!drflac__read_and_decode_next_frame(pFlac)) {
+ break; // Couldn't read the next frame, so just break from the loop and return.
+ }
+ }
+ else
+ {
+ // Here is where we grab the samples and interleave them.
+
+ unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
+ uint64_t totalSamplesInFrame = pFlac->currentFrame.header.blockSize * channelCount;
+ uint64_t samplesReadFromFrameSoFar = totalSamplesInFrame - pFlac->currentFrame.samplesRemaining;
+
+ int misalignedSampleCount = samplesReadFromFrameSoFar % channelCount;
+ if (misalignedSampleCount > 0) {
+ uint64_t misalignedSamplesRead = drflac__read_s32__misaligned(pFlac, misalignedSampleCount, bufferOut);
+ samplesRead += misalignedSamplesRead;
+ samplesReadFromFrameSoFar += misalignedSamplesRead;
+ bufferOut += misalignedSamplesRead;
+ samplesToRead -= misalignedSamplesRead;
+ }
+
+
+ uint64_t alignedSampleCountPerChannel = samplesToRead / channelCount;
+ if (alignedSampleCountPerChannel > pFlac->currentFrame.samplesRemaining / channelCount) {
+ alignedSampleCountPerChannel = pFlac->currentFrame.samplesRemaining / channelCount;
+ }
+
+ uint64_t firstAlignedSampleInFrame = samplesReadFromFrameSoFar / channelCount;
+ unsigned int unusedBitsPerSample = 32 - pFlac->bitsPerSample;
+
+ switch (pFlac->currentFrame.header.channelAssignment)
+ {
+ case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ {
+ const int* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame;
+ const int* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
+
+ for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) {
+ int left = pDecodedSamples0[i];
+ int side = pDecodedSamples1[i];
+ int right = left - side;
+
+ bufferOut[i*2+0] = left << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample);
+ bufferOut[i*2+1] = right << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample);
+ }
+ } break;
+
+ case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ {
+ const int* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame;
+ const int* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
+
+ for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) {
+ int side = pDecodedSamples0[i];
+ int right = pDecodedSamples1[i];
+ int left = right + side;
+
+ bufferOut[i*2+0] = left << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample);
+ bufferOut[i*2+1] = right << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample);
+ }
+ } break;
+
+ case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
+ {
+ const int* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame;
+ const int* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
+
+ for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) {
+ int side = pDecodedSamples1[i];
+ int mid = (((uint32_t)pDecodedSamples0[i]) << 1) | (side & 0x01);
+
+ bufferOut[i*2+0] = ((mid + side) >> 1) << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample);
+ bufferOut[i*2+1] = ((mid - side) >> 1) << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample);
+ }
+ } break;
+
+ case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
+ default:
+ {
+ if (pFlac->currentFrame.header.channelAssignment == 1) // 1 = Stereo
+ {
+ // Stereo optimized inner loop unroll.
+ const int* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame;
+ const int* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
+
+ for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) {
+ bufferOut[i*2+0] = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample);
+ bufferOut[i*2+1] = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample);
+ }
+ }
+ else
+ {
+ // Generic interleaving.
+ for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) {
+ for (unsigned int j = 0; j < channelCount; ++j) {
+ bufferOut[(i*channelCount)+j] = (pFlac->currentFrame.subframes[j].pDecodedSamples[firstAlignedSampleInFrame + i]) << (unusedBitsPerSample + pFlac->currentFrame.subframes[j].wastedBitsPerSample);
+ }
+ }
+ }
+ } break;
+ }
+
+ uint64_t alignedSamplesRead = alignedSampleCountPerChannel * channelCount;
+ samplesRead += alignedSamplesRead;
+ samplesReadFromFrameSoFar += alignedSamplesRead;
+ bufferOut += alignedSamplesRead;
+ samplesToRead -= alignedSamplesRead;
+ pFlac->currentFrame.samplesRemaining -= (unsigned int)alignedSamplesRead;
+
+
+
+ // At this point we may still have some excess samples left to read.
+ if (samplesToRead > 0 && pFlac->currentFrame.samplesRemaining > 0)
+ {
+ uint64_t excessSamplesRead = 0;
+ if (samplesToRead < pFlac->currentFrame.samplesRemaining) {
+ excessSamplesRead = drflac__read_s32__misaligned(pFlac, samplesToRead, bufferOut);
+ } else {
+ excessSamplesRead = drflac__read_s32__misaligned(pFlac, pFlac->currentFrame.samplesRemaining, bufferOut);
+ }
+
+ samplesRead += excessSamplesRead;
+ samplesReadFromFrameSoFar += excessSamplesRead;
+ bufferOut += excessSamplesRead;
+ samplesToRead -= excessSamplesRead;
+ }
+ }
+ }
+
+ return samplesRead;
+}
+
+uint64_t drflac_read_s16(drflac* pFlac, uint64_t samplesToRead, int16_t* pBufferOut)
+{
+ // This reads samples in 2 passes and can probably be optimized.
+ uint64_t samplesRead = 0;
+
+ while (samplesToRead > 0) {
+ int32_t samples32[4096];
+ uint64_t samplesJustRead = drflac_read_s32(pFlac, samplesToRead > 4096 ? 4096 : samplesToRead, samples32);
+ if (samplesJustRead == 0) {
+ break; // Reached the end.
+ }
+
+ // s32 -> s16
+ for (uint64_t i = 0; i < samplesJustRead; ++i) {
+ pBufferOut[i] = (int16_t)(samples32[i] >> 16);
+ }
+
+ samplesRead += samplesJustRead;
+ samplesToRead -= samplesJustRead;
+ pBufferOut += samplesJustRead;
+ }
+
+ return samplesRead;
+}
+
+dr_bool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex)
+{
+ if (pFlac == NULL) {
+ return DR_FALSE;
+ }
+
+ if (sampleIndex == 0) {
+ return drflac__seek_to_first_frame(pFlac);
+ }
+
+ // Clamp the sample to the end.
+ if (sampleIndex >= pFlac->totalSampleCount) {
+ sampleIndex = pFlac->totalSampleCount - 1;
+ }
+
+
+ // Different techniques depending on encapsulation. Using the native FLAC seektable with Ogg encapsulation is a bit awkward so
+ // we'll instead use Ogg's natural seeking facility.
+#ifndef DR_FLAC_NO_OGG
+ if (pFlac->container == drflac_container_ogg)
+ {
+ return drflac_ogg__seek_to_sample(pFlac, sampleIndex);
+ }
+ else
+#endif
+ {
+ // First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower.
+ if (!drflac__seek_to_sample__seek_table(pFlac, sampleIndex)) {
+ return drflac__seek_to_sample__brute_force(pFlac, sampleIndex);
+ }
+ }
+
+
+ return DR_TRUE;
+}
+
+
+
+//// High Level APIs ////
+
+int32_t* drflac__full_decode_and_close_s32(drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, uint64_t* totalSampleCountOut)
+{
+ assert(pFlac != NULL);
+
+ int32_t* pSampleData = NULL;
+ uint64_t totalSampleCount = pFlac->totalSampleCount;
+
+ if (totalSampleCount == 0)
+ {
+ int32_t buffer[4096];
+
+ size_t sampleDataBufferSize = sizeof(buffer);
+ pSampleData = (int32_t*)malloc(sampleDataBufferSize);
+ if (pSampleData == NULL) {
+ goto on_error;
+ }
+
+ uint64_t samplesRead;
+ while ((samplesRead = (uint64_t)drflac_read_s32(pFlac, sizeof(buffer)/sizeof(buffer[0]), buffer)) > 0)
+ {
+ if (((totalSampleCount + samplesRead) * sizeof(int32_t)) > sampleDataBufferSize) {
+ sampleDataBufferSize *= 2;
+ int32_t* pNewSampleData = (int32_t*)realloc(pSampleData, sampleDataBufferSize);
+ if (pNewSampleData == NULL) {
+ free(pSampleData);
+ goto on_error;
+ }
+
+ pSampleData = pNewSampleData;
+ }
+
+ memcpy(pSampleData + totalSampleCount, buffer, (size_t)(samplesRead*sizeof(int32_t)));
+ totalSampleCount += samplesRead;
+ }
+
+ // At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to
+ // protect those ears from random noise!
+ memset(pSampleData + totalSampleCount, 0, (size_t)(sampleDataBufferSize - totalSampleCount*sizeof(int32_t)));
+ }
+ else
+ {
+ uint64_t dataSize = totalSampleCount * sizeof(int32_t);
+ if (dataSize > SIZE_MAX) {
+ goto on_error; // The decoded data is too big.
+ }
+
+ pSampleData = (int32_t*)malloc((size_t)dataSize); // <-- Safe cast as per the check above.
+ if (pSampleData == NULL) {
+ goto on_error;
+ }
+
+ uint64_t samplesDecoded = drflac_read_s32(pFlac, pFlac->totalSampleCount, pSampleData);
+ if (samplesDecoded != pFlac->totalSampleCount) {
+ free(pSampleData);
+ goto on_error; // Something went wrong when decoding the FLAC stream.
+ }
+ }
+
+
+ if (sampleRateOut) *sampleRateOut = pFlac->sampleRate;
+ if (channelsOut) *channelsOut = pFlac->channels;
+ if (totalSampleCountOut) *totalSampleCountOut = totalSampleCount;
+
+ drflac_close(pFlac);
+ return pSampleData;
+
+on_error:
+ drflac_close(pFlac);
+ return NULL;
+}
+
+int16_t* drflac__full_decode_and_close_s16(drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, uint64_t* totalSampleCountOut)
+{
+ assert(pFlac != NULL);
+
+ int16_t* pSampleData = NULL;
+ uint64_t totalSampleCount = pFlac->totalSampleCount;
+
+ if (totalSampleCount == 0)
+ {
+ int16_t buffer[4096];
+
+ size_t sampleDataBufferSize = sizeof(buffer);
+ pSampleData = (int16_t*)malloc(sampleDataBufferSize);
+ if (pSampleData == NULL) {
+ goto on_error;
+ }
+
+ uint64_t samplesRead;
+ while ((samplesRead = (uint64_t)drflac_read_s16(pFlac, sizeof(buffer)/sizeof(buffer[0]), buffer)) > 0)
+ {
+ if (((totalSampleCount + samplesRead) * sizeof(int16_t)) > sampleDataBufferSize) {
+ sampleDataBufferSize *= 2;
+ int16_t* pNewSampleData = (int16_t*)realloc(pSampleData, sampleDataBufferSize);
+ if (pNewSampleData == NULL) {
+ free(pSampleData);
+ goto on_error;
+ }
+
+ pSampleData = pNewSampleData;
+ }
+
+ memcpy(pSampleData + totalSampleCount, buffer, (size_t)(samplesRead*sizeof(int16_t)));
+ totalSampleCount += samplesRead;
+ }
+
+ // At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to
+ // protect those ears from random noise!
+ memset(pSampleData + totalSampleCount, 0, (size_t)(sampleDataBufferSize - totalSampleCount*sizeof(int16_t)));
+ }
+ else
+ {
+ uint64_t dataSize = totalSampleCount * sizeof(int16_t);
+ if (dataSize > SIZE_MAX) {
+ goto on_error; // The decoded data is too big.
+ }
+
+ pSampleData = (int16_t*)malloc((size_t)dataSize); // <-- Safe cast as per the check above.
+ if (pSampleData == NULL) {
+ goto on_error;
+ }
+
+ uint64_t samplesDecoded = drflac_read_s16(pFlac, pFlac->totalSampleCount, pSampleData);
+ if (samplesDecoded != pFlac->totalSampleCount) {
+ free(pSampleData);
+ goto on_error; // Something went wrong when decoding the FLAC stream.
+ }
+ }
+
+
+ if (sampleRateOut) *sampleRateOut = pFlac->sampleRate;
+ if (channelsOut) *channelsOut = pFlac->channels;
+ if (totalSampleCountOut) *totalSampleCountOut = totalSampleCount;
+
+ drflac_close(pFlac);
+ return pSampleData;
+
+on_error:
+ drflac_close(pFlac);
+ return NULL;
+}
+
+int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ // Safety.
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open(onRead, onSeek, pUserData);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+int16_t* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ // Safety.
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open(onRead, onSeek, pUserData);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+#ifndef DR_FLAC_NO_STDIO
+int32_t* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open_file(filename);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+int16_t* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open_file(filename);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount);
+}
+#endif
+
+int32_t* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open_memory(data, dataSize);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+int16_t* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open_memory(data, dataSize);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+void drflac_free(void* pSampleDataReturnedByOpenAndDecode)
+{
+ free(pSampleDataReturnedByOpenAndDecode);
+}
+
+
+
+
+void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, uint32_t commentCount, const char* pComments)
+{
+ if (pIter == NULL) {
+ return;
+ }
+
+ pIter->countRemaining = commentCount;
+ pIter->pRunningData = pComments;
+}
+
+const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, uint32_t* pCommentLengthOut)
+{
+ // Safety.
+ if (pCommentLengthOut) *pCommentLengthOut = 0;
+
+ if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
+ return NULL;
+ }
+
+ uint32_t length = drflac__le2host_32(*(uint32_t*)pIter->pRunningData);
+ pIter->pRunningData += 4;
+
+ const char* pComment = pIter->pRunningData;
+ pIter->pRunningData += length;
+ pIter->countRemaining -= 1;
+
+ if (pCommentLengthOut) *pCommentLengthOut = length;
+ return pComment;
+}
+#endif //DR_FLAC_IMPLEMENTATION
+
+
+// REVISION HISTORY
+//
+// v0.4c - 2016-12-26
+// - Add support for signed 16-bit integer PCM decoding.
+//
+// v0.4b - 2016-10-23
+// - A minor change to dr_bool8 and dr_bool32 types.
+//
+// v0.4a - 2016-10-11
+// - Rename drBool32 to dr_bool32 for styling consistency.
+//
+// v0.4 - 2016-09-29
+// - API/ABI CHANGE: Use fixed size 32-bit booleans instead of the built-in bool type.
+// - API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32()
+// - API CHANGE: Swap the order of "channels" and "sampleRate" parameters in drflac_open_and_decode*(). Rationale for this is to
+// keep it consistent with dr_audio.
+//
+// v0.3f - 2016-09-21
+// - Fix a warning with GCC.
+//
+// v0.3e - 2016-09-18
+// - Fixed a bug where GCC 4.3+ was not getting properly identified.
+// - Fixed a few typos.
+// - Changed date formats to ISO 8601 (YYYY-MM-DD).
+//
+// v0.3d - 2016-06-11
+// - Minor clean up.
+//
+// v0.3c - 2016-05-28
+// - Fixed compilation error.
+//
+// v0.3b - 2016-05-16
+// - Fixed Linux/GCC build.
+// - Updated documentation.
+//
+// v0.3a - 2016-05-15
+// - Minor fixes to documentation.
+//
+// v0.3 - 2016-05-11
+// - Optimizations. Now at about parity with the reference implementation on 32-bit builds.
+// - Lots of clean up.
+//
+// v0.2b - 2016-05-10
+// - Bug fixes.
+//
+// v0.2a - 2016-05-10
+// - Made drflac_open_and_decode() more robust.
+// - Removed an unused debugging variable
+//
+// v0.2 - 2016-05-09
+// - Added support for Ogg encapsulation.
+// - API CHANGE. Have the onSeek callback take a third argument which specifies whether or not the seek
+// should be relative to the start or the current position. Also changes the seeking rules such that
+// seeking offsets will never be negative.
+// - Have drflac_open_and_decode() fail gracefully if the stream has an unknown total sample count.
+//
+// v0.1b - 2016-05-07
+// - Properly close the file handle in drflac_open_file() and family when the decoder fails to initialize.
+// - Removed a stale comment.
+//
+// v0.1a - 2016-05-05
+// - Minor formatting changes.
+// - Fixed a warning on the GCC build.
+//
+// v0.1 - 2016-05-03
+// - Initial versioned release.
+
+
+// TODO
+// - Add support for initializing the decoder without a header STREAMINFO block.
+// - Test CUESHEET metadata blocks.
+
+
+/*
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+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 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.
+
+For more information, please refer to <http://unlicense.org/>
+*/
diff --git a/src/external/glad.h b/src/external/glad.h
new file mode 100644
index 00000000..ab5947e6
--- /dev/null
+++ b/src/external/glad.h
@@ -0,0 +1,5441 @@
+/*
+
+ OpenGL loader generated by glad 0.1.10a0 on Fri Jun 10 12:54:12 2016.
+
+ Language/Generator: C/C++
+ Specification: gl
+ APIs: gl=3.3
+ Profile: core
+ Extensions:
+ GL_AMD_debug_output, GL_AMD_query_buffer_object, GL_ARB_ES2_compatibility, GL_ARB_ES3_compatibility, GL_ARB_buffer_storage, GL_ARB_compatibility, GL_ARB_compressed_texture_pixel_storage, GL_ARB_debug_output, GL_ARB_depth_buffer_float, GL_ARB_depth_clamp, GL_ARB_depth_texture, GL_ARB_draw_buffers, GL_ARB_draw_buffers_blend, GL_ARB_explicit_attrib_location, GL_ARB_explicit_uniform_location, GL_ARB_fragment_program, GL_ARB_fragment_shader, GL_ARB_framebuffer_object, GL_ARB_framebuffer_sRGB, GL_ARB_multisample, GL_ARB_sample_locations, GL_ARB_texture_compression, GL_ARB_texture_float, GL_ARB_texture_multisample, GL_ARB_texture_non_power_of_two, GL_ARB_texture_rg, GL_ARB_texture_swizzle, GL_ARB_uniform_buffer_object, GL_ARB_vertex_array_object, GL_ARB_vertex_attrib_binding, GL_ARB_vertex_buffer_object, GL_ARB_vertex_program, GL_ARB_vertex_shader, GL_ATI_element_array, GL_ATI_fragment_shader, GL_ATI_vertex_array_object, GL_EXT_blend_color, GL_EXT_blend_equation_separate, GL_EXT_blend_func_separate, GL_EXT_framebuffer_blit, GL_EXT_framebuffer_multisample, GL_EXT_framebuffer_multisample_blit_scaled, GL_EXT_framebuffer_object, GL_EXT_framebuffer_sRGB, GL_EXT_index_array_formats, GL_EXT_texture, GL_EXT_texture_compression_s3tc, GL_EXT_texture_sRGB, GL_EXT_texture_swizzle, GL_EXT_vertex_array, GL_EXT_vertex_shader
+ Loader: No
+
+ Commandline:
+ --profile="core" --api="gl=3.3" --generator="c" --spec="gl" --no-loader --extensions="GL_AMD_debug_output,GL_AMD_query_buffer_object,GL_ARB_ES2_compatibility,GL_ARB_ES3_compatibility,GL_ARB_buffer_storage,GL_ARB_compatibility,GL_ARB_compressed_texture_pixel_storage,GL_ARB_debug_output,GL_ARB_depth_buffer_float,GL_ARB_depth_clamp,GL_ARB_depth_texture,GL_ARB_draw_buffers,GL_ARB_draw_buffers_blend,GL_ARB_explicit_attrib_location,GL_ARB_explicit_uniform_location,GL_ARB_fragment_program,GL_ARB_fragment_shader,GL_ARB_framebuffer_object,GL_ARB_framebuffer_sRGB,GL_ARB_multisample,GL_ARB_sample_locations,GL_ARB_texture_compression,GL_ARB_texture_float,GL_ARB_texture_multisample,GL_ARB_texture_non_power_of_two,GL_ARB_texture_rg,GL_ARB_texture_swizzle,GL_ARB_uniform_buffer_object,GL_ARB_vertex_array_object,GL_ARB_vertex_attrib_binding,GL_ARB_vertex_buffer_object,GL_ARB_vertex_program,GL_ARB_vertex_shader,GL_ATI_element_array,GL_ATI_fragment_shader,GL_ATI_vertex_array_object,GL_EXT_blend_color,GL_EXT_blend_equation_separate,GL_EXT_blend_func_separate,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_multisample_blit_scaled,GL_EXT_framebuffer_object,GL_EXT_framebuffer_sRGB,GL_EXT_index_array_formats,GL_EXT_texture,GL_EXT_texture_compression_s3tc,GL_EXT_texture_sRGB,GL_EXT_texture_swizzle,GL_EXT_vertex_array,GL_EXT_vertex_shader"
+ Online:
+ http://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D3.3&extensions=GL_AMD_debug_output&extensions=GL_AMD_query_buffer_object&extensions=GL_ARB_ES2_compatibility&extensions=GL_ARB_ES3_compatibility&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_compatibility&extensions=GL_ARB_compressed_texture_pixel_storage&extensions=GL_ARB_debug_output&extensions=GL_ARB_depth_buffer_float&extensions=GL_ARB_depth_clamp&extensions=GL_ARB_depth_texture&extensions=GL_ARB_draw_buffers&extensions=GL_ARB_draw_buffers_blend&extensions=GL_ARB_explicit_attrib_location&extensions=GL_ARB_explicit_uniform_location&extensions=GL_ARB_fragment_program&extensions=GL_ARB_fragment_shader&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_framebuffer_sRGB&extensions=GL_ARB_multisample&extensions=GL_ARB_sample_locations&extensions=GL_ARB_texture_compression&extensions=GL_ARB_texture_float&extensions=GL_ARB_texture_multisample&extensions=GL_ARB_texture_non_power_of_two&extensions=GL_ARB_texture_rg&extensions=GL_ARB_texture_swizzle&extensions=GL_ARB_uniform_buffer_object&extensions=GL_ARB_vertex_array_object&extensions=GL_ARB_vertex_attrib_binding&extensions=GL_ARB_vertex_buffer_object&extensions=GL_ARB_vertex_program&extensions=GL_ARB_vertex_shader&extensions=GL_ATI_element_array&extensions=GL_ATI_fragment_shader&extensions=GL_ATI_vertex_array_object&extensions=GL_EXT_blend_color&extensions=GL_EXT_blend_equation_separate&extensions=GL_EXT_blend_func_separate&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_multisample_blit_scaled&extensions=GL_EXT_framebuffer_object&extensions=GL_EXT_framebuffer_sRGB&extensions=GL_EXT_index_array_formats&extensions=GL_EXT_texture&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_sRGB&extensions=GL_EXT_texture_swizzle&extensions=GL_EXT_vertex_array&extensions=GL_EXT_vertex_shader
+*/
+
+
+#ifndef __glad_h_
+#define __glad_h_
+
+#ifdef __gl_h_
+#error OpenGL header already included, remove this include, glad already provides it
+#endif
+#define __gl_h_
+
+#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+//#include <windows.h>
+#define APIENTRY __stdcall // RAY: Added
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct gladGLversionStruct {
+ int major;
+ int minor;
+};
+
+typedef void* (* GLADloadproc)(const char *name);
+
+#ifndef GLAPI
+# if defined(GLAD_GLAPI_EXPORT)
+# if defined(WIN32) || defined(__CYGWIN__)
+# if defined(GLAD_GLAPI_EXPORT_BUILD)
+# if defined(__GNUC__)
+# define GLAPI __attribute__ ((dllexport)) extern
+# else
+# define GLAPI __declspec(dllexport) extern
+# endif
+# else
+# if defined(__GNUC__)
+# define GLAPI __attribute__ ((dllimport)) extern
+# else
+# define GLAPI __declspec(dllimport) extern
+# endif
+# endif
+# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD)
+# define GLAPI __attribute__ ((visibility ("default"))) extern
+# else
+# define GLAPI extern
+# endif
+# else
+# define GLAPI extern
+# endif
+#endif
+
+GLAPI struct gladGLversionStruct GLVersion;
+GLAPI int gladLoadGLLoader(GLADloadproc);
+
+#include <stddef.h>
+//#include <KHR/khrplatform.h> // RAY: Not required
+#ifndef GLEXT_64_TYPES_DEFINED
+/* This code block is duplicated in glxext.h, so must be protected */
+#define GLEXT_64_TYPES_DEFINED
+/* Define int32_t, int64_t, and uint64_t types for UST/MSC */
+/* (as used in the GL_EXT_timer_query extension). */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+#elif defined(__sun__) || defined(__digital__)
+#include <inttypes.h>
+#if defined(__STDC__)
+#if defined(__arch64__) || defined(_LP64)
+typedef long int int64_t;
+typedef unsigned long int uint64_t;
+#else
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#endif /* __arch64__ */
+#endif /* __STDC__ */
+#elif defined( __VMS ) || defined(__sgi)
+#include <inttypes.h>
+#elif defined(__SCO__) || defined(__USLC__)
+#include <stdint.h>
+#elif defined(__UNIXOS2__) || defined(__SOL64__)
+typedef long int int32_t;
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#elif defined(_WIN32) && defined(__GNUC__)
+#include <stdint.h>
+#elif defined(_WIN32)
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+/* Fallback if nothing above works */
+#include <inttypes.h>
+#endif
+#endif
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef void GLvoid;
+typedef signed char GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLclampx;
+typedef unsigned char GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef int GLsizei;
+typedef float GLfloat;
+typedef float GLclampf;
+typedef double GLdouble;
+typedef double GLclampd;
+typedef void *GLeglImageOES;
+typedef char GLchar;
+typedef char GLcharARB;
+#ifdef __APPLE__
+typedef void *GLhandleARB;
+#else
+typedef unsigned int GLhandleARB;
+#endif
+typedef unsigned short GLhalfARB;
+typedef unsigned short GLhalf;
+typedef GLint GLfixed;
+typedef ptrdiff_t GLintptr;
+typedef ptrdiff_t GLsizeiptr;
+typedef int64_t GLint64;
+typedef uint64_t GLuint64;
+typedef ptrdiff_t GLintptrARB;
+typedef ptrdiff_t GLsizeiptrARB;
+typedef int64_t GLint64EXT;
+typedef uint64_t GLuint64EXT;
+typedef struct __GLsync *GLsync;
+struct _cl_context;
+struct _cl_event;
+typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);
+typedef unsigned short GLhalfNV;
+typedef GLintptr GLvdpauSurfaceNV;
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#define GL_FALSE 0
+#define GL_TRUE 1
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+#define GL_NONE 0
+#define GL_FRONT_LEFT 0x0400
+#define GL_FRONT_RIGHT 0x0401
+#define GL_BACK_LEFT 0x0402
+#define GL_BACK_RIGHT 0x0403
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_LEFT 0x0406
+#define GL_RIGHT 0x0407
+#define GL_FRONT_AND_BACK 0x0408
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_OUT_OF_MEMORY 0x0505
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+#define GL_POINT_SIZE 0x0B11
+#define GL_POINT_SIZE_RANGE 0x0B12
+#define GL_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_LINE_SMOOTH 0x0B20
+#define GL_LINE_WIDTH 0x0B21
+#define GL_LINE_WIDTH_RANGE 0x0B22
+#define GL_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_POLYGON_MODE 0x0B40
+#define GL_POLYGON_SMOOTH 0x0B41
+#define GL_CULL_FACE 0x0B44
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_TEST 0x0B71
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_TEST 0x0B90
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_VIEWPORT 0x0BA2
+#define GL_DITHER 0x0BD0
+#define GL_BLEND_DST 0x0BE0
+#define GL_BLEND_SRC 0x0BE1
+#define GL_BLEND 0x0BE2
+#define GL_LOGIC_OP_MODE 0x0BF0
+#define GL_COLOR_LOGIC_OP 0x0BF2
+#define GL_DRAW_BUFFER 0x0C01
+#define GL_READ_BUFFER 0x0C02
+#define GL_SCISSOR_BOX 0x0C10
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_DOUBLEBUFFER 0x0C32
+#define GL_STEREO 0x0C33
+#define GL_LINE_SMOOTH_HINT 0x0C52
+#define GL_POLYGON_SMOOTH_HINT 0x0C53
+#define GL_UNPACK_SWAP_BYTES 0x0CF0
+#define GL_UNPACK_LSB_FIRST 0x0CF1
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GL_UNPACK_SKIP_ROWS 0x0CF3
+#define GL_UNPACK_SKIP_PIXELS 0x0CF4
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_SWAP_BYTES 0x0D00
+#define GL_PACK_LSB_FIRST 0x0D01
+#define GL_PACK_ROW_LENGTH 0x0D02
+#define GL_PACK_SKIP_ROWS 0x0D03
+#define GL_PACK_SKIP_PIXELS 0x0D04
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_TEXTURE_1D 0x0DE0
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+#define GL_POLYGON_OFFSET_POINT 0x2A01
+#define GL_POLYGON_OFFSET_LINE 0x2A02
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_1D 0x8068
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_TEXTURE_WIDTH 0x1000
+#define GL_TEXTURE_HEIGHT 0x1001
+#define GL_TEXTURE_INTERNAL_FORMAT 0x1003
+#define GL_TEXTURE_BORDER_COLOR 0x1004
+#define GL_TEXTURE_RED_SIZE 0x805C
+#define GL_TEXTURE_GREEN_SIZE 0x805D
+#define GL_TEXTURE_BLUE_SIZE 0x805E
+#define GL_TEXTURE_ALPHA_SIZE 0x805F
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_DOUBLE 0x140A
+#define GL_CLEAR 0x1500
+#define GL_AND 0x1501
+#define GL_AND_REVERSE 0x1502
+#define GL_COPY 0x1503
+#define GL_AND_INVERTED 0x1504
+#define GL_NOOP 0x1505
+#define GL_XOR 0x1506
+#define GL_OR 0x1507
+#define GL_NOR 0x1508
+#define GL_EQUIV 0x1509
+#define GL_INVERT 0x150A
+#define GL_OR_REVERSE 0x150B
+#define GL_COPY_INVERTED 0x150C
+#define GL_OR_INVERTED 0x150D
+#define GL_NAND 0x150E
+#define GL_SET 0x150F
+#define GL_TEXTURE 0x1702
+#define GL_COLOR 0x1800
+#define GL_DEPTH 0x1801
+#define GL_STENCIL 0x1802
+#define GL_STENCIL_INDEX 0x1901
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_RED 0x1903
+#define GL_GREEN 0x1904
+#define GL_BLUE 0x1905
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_POINT 0x1B00
+#define GL_LINE 0x1B01
+#define GL_FILL 0x1B02
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_PROXY_TEXTURE_1D 0x8063
+#define GL_PROXY_TEXTURE_2D 0x8064
+#define GL_REPEAT 0x2901
+#define GL_R3_G3_B2 0x2A10
+#define GL_RGB4 0x804F
+#define GL_RGB5 0x8050
+#define GL_RGB8 0x8051
+#define GL_RGB10 0x8052
+#define GL_RGB12 0x8053
+#define GL_RGB16 0x8054
+#define GL_RGBA2 0x8055
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGBA8 0x8058
+#define GL_RGB10_A2 0x8059
+#define GL_RGBA12 0x805A
+#define GL_RGBA16 0x805B
+#define GL_UNSIGNED_BYTE_3_3_2 0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_INT_8_8_8_8 0x8035
+#define GL_UNSIGNED_INT_10_10_10_2 0x8036
+#define GL_TEXTURE_BINDING_3D 0x806A
+#define GL_PACK_SKIP_IMAGES 0x806B
+#define GL_PACK_IMAGE_HEIGHT 0x806C
+#define GL_UNPACK_SKIP_IMAGES 0x806D
+#define GL_UNPACK_IMAGE_HEIGHT 0x806E
+#define GL_TEXTURE_3D 0x806F
+#define GL_PROXY_TEXTURE_3D 0x8070
+#define GL_TEXTURE_DEPTH 0x8071
+#define GL_TEXTURE_WRAP_R 0x8072
+#define GL_MAX_3D_TEXTURE_SIZE 0x8073
+#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#define GL_BGR 0x80E0
+#define GL_BGRA 0x80E1
+#define GL_MAX_ELEMENTS_VERTICES 0x80E8
+#define GL_MAX_ELEMENTS_INDICES 0x80E9
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_TEXTURE_MIN_LOD 0x813A
+#define GL_TEXTURE_MAX_LOD 0x813B
+#define GL_TEXTURE_BASE_LEVEL 0x813C
+#define GL_TEXTURE_MAX_LEVEL 0x813D
+#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+#define GL_MULTISAMPLE 0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
+#define GL_SAMPLE_COVERAGE 0x80A0
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+#define GL_COMPRESSED_RGB 0x84ED
+#define GL_COMPRESSED_RGBA 0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT 0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0
+#define GL_TEXTURE_COMPRESSED 0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+#define GL_CLAMP_TO_BORDER 0x812D
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_DEPTH_COMPONENT24 0x81A6
+#define GL_DEPTH_COMPONENT32 0x81A7
+#define GL_MIRRORED_REPEAT 0x8370
+#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
+#define GL_TEXTURE_LOD_BIAS 0x8501
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+#define GL_TEXTURE_DEPTH_SIZE 0x884A
+#define GL_TEXTURE_COMPARE_MODE 0x884C
+#define GL_TEXTURE_COMPARE_FUNC 0x884D
+#define GL_FUNC_ADD 0x8006
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+#define GL_MIN 0x8007
+#define GL_MAX 0x8008
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+#define GL_QUERY_COUNTER_BITS 0x8864
+#define GL_CURRENT_QUERY 0x8865
+#define GL_QUERY_RESULT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE 0x8867
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+#define GL_READ_ONLY 0x88B8
+#define GL_WRITE_ONLY 0x88B9
+#define GL_READ_WRITE 0x88BA
+#define GL_BUFFER_ACCESS 0x88BB
+#define GL_BUFFER_MAPPED 0x88BC
+#define GL_BUFFER_MAP_POINTER 0x88BD
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STREAM_READ 0x88E1
+#define GL_STREAM_COPY 0x88E2
+#define GL_STATIC_DRAW 0x88E4
+#define GL_STATIC_READ 0x88E5
+#define GL_STATIC_COPY 0x88E6
+#define GL_DYNAMIC_DRAW 0x88E8
+#define GL_DYNAMIC_READ 0x88E9
+#define GL_DYNAMIC_COPY 0x88EA
+#define GL_SAMPLES_PASSED 0x8914
+#define GL_SRC1_ALPHA 0x8589
+#define GL_BLEND_EQUATION_RGB 0x8009
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_MAX_DRAW_BUFFERS 0x8824
+#define GL_DRAW_BUFFER0 0x8825
+#define GL_DRAW_BUFFER1 0x8826
+#define GL_DRAW_BUFFER2 0x8827
+#define GL_DRAW_BUFFER3 0x8828
+#define GL_DRAW_BUFFER4 0x8829
+#define GL_DRAW_BUFFER5 0x882A
+#define GL_DRAW_BUFFER6 0x882B
+#define GL_DRAW_BUFFER7 0x882C
+#define GL_DRAW_BUFFER8 0x882D
+#define GL_DRAW_BUFFER9 0x882E
+#define GL_DRAW_BUFFER10 0x882F
+#define GL_DRAW_BUFFER11 0x8830
+#define GL_DRAW_BUFFER12 0x8831
+#define GL_DRAW_BUFFER13 0x8832
+#define GL_DRAW_BUFFER14 0x8833
+#define GL_DRAW_BUFFER15 0x8834
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
+#define GL_MAX_VARYING_FLOATS 0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_1D 0x8B5D
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_3D 0x8B5F
+#define GL_SAMPLER_CUBE 0x8B60
+#define GL_SAMPLER_1D_SHADOW 0x8B61
+#define GL_SAMPLER_2D_SHADOW 0x8B62
+#define GL_DELETE_STATUS 0x8B80
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0
+#define GL_LOWER_LEFT 0x8CA1
+#define GL_UPPER_LEFT 0x8CA2
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_PIXEL_PACK_BUFFER 0x88EB
+#define GL_PIXEL_UNPACK_BUFFER 0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
+#define GL_FLOAT_MAT2x3 0x8B65
+#define GL_FLOAT_MAT2x4 0x8B66
+#define GL_FLOAT_MAT3x2 0x8B67
+#define GL_FLOAT_MAT3x4 0x8B68
+#define GL_FLOAT_MAT4x2 0x8B69
+#define GL_FLOAT_MAT4x3 0x8B6A
+#define GL_SRGB 0x8C40
+#define GL_SRGB8 0x8C41
+#define GL_SRGB_ALPHA 0x8C42
+#define GL_SRGB8_ALPHA8 0x8C43
+#define GL_COMPRESSED_SRGB 0x8C48
+#define GL_COMPRESSED_SRGB_ALPHA 0x8C49
+#define GL_COMPARE_REF_TO_TEXTURE 0x884E
+#define GL_CLIP_DISTANCE0 0x3000
+#define GL_CLIP_DISTANCE1 0x3001
+#define GL_CLIP_DISTANCE2 0x3002
+#define GL_CLIP_DISTANCE3 0x3003
+#define GL_CLIP_DISTANCE4 0x3004
+#define GL_CLIP_DISTANCE5 0x3005
+#define GL_CLIP_DISTANCE6 0x3006
+#define GL_CLIP_DISTANCE7 0x3007
+#define GL_MAX_CLIP_DISTANCES 0x0D32
+#define GL_MAJOR_VERSION 0x821B
+#define GL_MINOR_VERSION 0x821C
+#define GL_NUM_EXTENSIONS 0x821D
+#define GL_CONTEXT_FLAGS 0x821E
+#define GL_COMPRESSED_RED 0x8225
+#define GL_COMPRESSED_RG 0x8226
+#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
+#define GL_RGBA32F 0x8814
+#define GL_RGB32F 0x8815
+#define GL_RGBA16F 0x881A
+#define GL_RGB16F 0x881B
+#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD
+#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
+#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904
+#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905
+#define GL_CLAMP_READ_COLOR 0x891C
+#define GL_FIXED_ONLY 0x891D
+#define GL_MAX_VARYING_COMPONENTS 0x8B4B
+#define GL_TEXTURE_1D_ARRAY 0x8C18
+#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19
+#define GL_TEXTURE_2D_ARRAY 0x8C1A
+#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B
+#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C
+#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
+#define GL_R11F_G11F_B10F 0x8C3A
+#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
+#define GL_RGB9_E5 0x8C3D
+#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E
+#define GL_TEXTURE_SHARED_SIZE 0x8C3F
+#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76
+#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80
+#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83
+#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84
+#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85
+#define GL_PRIMITIVES_GENERATED 0x8C87
+#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
+#define GL_RASTERIZER_DISCARD 0x8C89
+#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B
+#define GL_INTERLEAVED_ATTRIBS 0x8C8C
+#define GL_SEPARATE_ATTRIBS 0x8C8D
+#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F
+#define GL_RGBA32UI 0x8D70
+#define GL_RGB32UI 0x8D71
+#define GL_RGBA16UI 0x8D76
+#define GL_RGB16UI 0x8D77
+#define GL_RGBA8UI 0x8D7C
+#define GL_RGB8UI 0x8D7D
+#define GL_RGBA32I 0x8D82
+#define GL_RGB32I 0x8D83
+#define GL_RGBA16I 0x8D88
+#define GL_RGB16I 0x8D89
+#define GL_RGBA8I 0x8D8E
+#define GL_RGB8I 0x8D8F
+#define GL_RED_INTEGER 0x8D94
+#define GL_GREEN_INTEGER 0x8D95
+#define GL_BLUE_INTEGER 0x8D96
+#define GL_RGB_INTEGER 0x8D98
+#define GL_RGBA_INTEGER 0x8D99
+#define GL_BGR_INTEGER 0x8D9A
+#define GL_BGRA_INTEGER 0x8D9B
+#define GL_SAMPLER_1D_ARRAY 0x8DC0
+#define GL_SAMPLER_2D_ARRAY 0x8DC1
+#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3
+#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
+#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
+#define GL_UNSIGNED_INT_VEC2 0x8DC6
+#define GL_UNSIGNED_INT_VEC3 0x8DC7
+#define GL_UNSIGNED_INT_VEC4 0x8DC8
+#define GL_INT_SAMPLER_1D 0x8DC9
+#define GL_INT_SAMPLER_2D 0x8DCA
+#define GL_INT_SAMPLER_3D 0x8DCB
+#define GL_INT_SAMPLER_CUBE 0x8DCC
+#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE
+#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
+#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1
+#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
+#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
+#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
+#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
+#define GL_QUERY_WAIT 0x8E13
+#define GL_QUERY_NO_WAIT 0x8E14
+#define GL_QUERY_BY_REGION_WAIT 0x8E15
+#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16
+#define GL_BUFFER_ACCESS_FLAGS 0x911F
+#define GL_BUFFER_MAP_LENGTH 0x9120
+#define GL_BUFFER_MAP_OFFSET 0x9121
+#define GL_DEPTH_COMPONENT32F 0x8CAC
+#define GL_DEPTH32F_STENCIL8 0x8CAD
+#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
+#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
+#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
+#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
+#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
+#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
+#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
+#define GL_FRAMEBUFFER_DEFAULT 0x8218
+#define GL_FRAMEBUFFER_UNDEFINED 0x8219
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+#define GL_DEPTH_STENCIL 0x84F9
+#define GL_UNSIGNED_INT_24_8 0x84FA
+#define GL_DEPTH24_STENCIL8 0x88F0
+#define GL_TEXTURE_STENCIL_SIZE 0x88F1
+#define GL_TEXTURE_RED_TYPE 0x8C10
+#define GL_TEXTURE_GREEN_TYPE 0x8C11
+#define GL_TEXTURE_BLUE_TYPE 0x8C12
+#define GL_TEXTURE_ALPHA_TYPE 0x8C13
+#define GL_TEXTURE_DEPTH_TYPE 0x8C16
+#define GL_UNSIGNED_NORMALIZED 0x8C17
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
+#define GL_RENDERBUFFER_SAMPLES 0x8CAB
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_COLOR_ATTACHMENT1 0x8CE1
+#define GL_COLOR_ATTACHMENT2 0x8CE2
+#define GL_COLOR_ATTACHMENT3 0x8CE3
+#define GL_COLOR_ATTACHMENT4 0x8CE4
+#define GL_COLOR_ATTACHMENT5 0x8CE5
+#define GL_COLOR_ATTACHMENT6 0x8CE6
+#define GL_COLOR_ATTACHMENT7 0x8CE7
+#define GL_COLOR_ATTACHMENT8 0x8CE8
+#define GL_COLOR_ATTACHMENT9 0x8CE9
+#define GL_COLOR_ATTACHMENT10 0x8CEA
+#define GL_COLOR_ATTACHMENT11 0x8CEB
+#define GL_COLOR_ATTACHMENT12 0x8CEC
+#define GL_COLOR_ATTACHMENT13 0x8CED
+#define GL_COLOR_ATTACHMENT14 0x8CEE
+#define GL_COLOR_ATTACHMENT15 0x8CEF
+#define GL_COLOR_ATTACHMENT16 0x8CF0
+#define GL_COLOR_ATTACHMENT17 0x8CF1
+#define GL_COLOR_ATTACHMENT18 0x8CF2
+#define GL_COLOR_ATTACHMENT19 0x8CF3
+#define GL_COLOR_ATTACHMENT20 0x8CF4
+#define GL_COLOR_ATTACHMENT21 0x8CF5
+#define GL_COLOR_ATTACHMENT22 0x8CF6
+#define GL_COLOR_ATTACHMENT23 0x8CF7
+#define GL_COLOR_ATTACHMENT24 0x8CF8
+#define GL_COLOR_ATTACHMENT25 0x8CF9
+#define GL_COLOR_ATTACHMENT26 0x8CFA
+#define GL_COLOR_ATTACHMENT27 0x8CFB
+#define GL_COLOR_ATTACHMENT28 0x8CFC
+#define GL_COLOR_ATTACHMENT29 0x8CFD
+#define GL_COLOR_ATTACHMENT30 0x8CFE
+#define GL_COLOR_ATTACHMENT31 0x8CFF
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_STENCIL_INDEX1 0x8D46
+#define GL_STENCIL_INDEX4 0x8D47
+#define GL_STENCIL_INDEX8 0x8D48
+#define GL_STENCIL_INDEX16 0x8D49
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
+#define GL_MAX_SAMPLES 0x8D57
+#define GL_INDEX 0x8222
+#define GL_FRAMEBUFFER_SRGB 0x8DB9
+#define GL_HALF_FLOAT 0x140B
+#define GL_MAP_READ_BIT 0x0001
+#define GL_MAP_WRITE_BIT 0x0002
+#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
+#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
+#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
+#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
+#define GL_COMPRESSED_RED_RGTC1 0x8DBB
+#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
+#define GL_COMPRESSED_RG_RGTC2 0x8DBD
+#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
+#define GL_RG 0x8227
+#define GL_RG_INTEGER 0x8228
+#define GL_R8 0x8229
+#define GL_R16 0x822A
+#define GL_RG8 0x822B
+#define GL_RG16 0x822C
+#define GL_R16F 0x822D
+#define GL_R32F 0x822E
+#define GL_RG16F 0x822F
+#define GL_RG32F 0x8230
+#define GL_R8I 0x8231
+#define GL_R8UI 0x8232
+#define GL_R16I 0x8233
+#define GL_R16UI 0x8234
+#define GL_R32I 0x8235
+#define GL_R32UI 0x8236
+#define GL_RG8I 0x8237
+#define GL_RG8UI 0x8238
+#define GL_RG16I 0x8239
+#define GL_RG16UI 0x823A
+#define GL_RG32I 0x823B
+#define GL_RG32UI 0x823C
+#define GL_VERTEX_ARRAY_BINDING 0x85B5
+#define GL_SAMPLER_2D_RECT 0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64
+#define GL_SAMPLER_BUFFER 0x8DC2
+#define GL_INT_SAMPLER_2D_RECT 0x8DCD
+#define GL_INT_SAMPLER_BUFFER 0x8DD0
+#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8
+#define GL_TEXTURE_BUFFER 0x8C2A
+#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B
+#define GL_TEXTURE_BINDING_BUFFER 0x8C2C
+#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D
+#define GL_TEXTURE_RECTANGLE 0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8
+#define GL_R8_SNORM 0x8F94
+#define GL_RG8_SNORM 0x8F95
+#define GL_RGB8_SNORM 0x8F96
+#define GL_RGBA8_SNORM 0x8F97
+#define GL_R16_SNORM 0x8F98
+#define GL_RG16_SNORM 0x8F99
+#define GL_RGB16_SNORM 0x8F9A
+#define GL_RGBA16_SNORM 0x8F9B
+#define GL_SIGNED_NORMALIZED 0x8F9C
+#define GL_PRIMITIVE_RESTART 0x8F9D
+#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E
+#define GL_COPY_READ_BUFFER 0x8F36
+#define GL_COPY_WRITE_BUFFER 0x8F37
+#define GL_UNIFORM_BUFFER 0x8A11
+#define GL_UNIFORM_BUFFER_BINDING 0x8A28
+#define GL_UNIFORM_BUFFER_START 0x8A29
+#define GL_UNIFORM_BUFFER_SIZE 0x8A2A
+#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
+#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C
+#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
+#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
+#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
+#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30
+#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
+#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32
+#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
+#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
+#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
+#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
+#define GL_UNIFORM_TYPE 0x8A37
+#define GL_UNIFORM_SIZE 0x8A38
+#define GL_UNIFORM_NAME_LENGTH 0x8A39
+#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
+#define GL_UNIFORM_OFFSET 0x8A3B
+#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
+#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
+#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E
+#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
+#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
+#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
+#define GL_INVALID_INDEX 0xFFFFFFFF
+#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
+#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define GL_LINES_ADJACENCY 0x000A
+#define GL_LINE_STRIP_ADJACENCY 0x000B
+#define GL_TRIANGLES_ADJACENCY 0x000C
+#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D
+#define GL_PROGRAM_POINT_SIZE 0x8642
+#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29
+#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8
+#define GL_GEOMETRY_SHADER 0x8DD9
+#define GL_GEOMETRY_VERTICES_OUT 0x8916
+#define GL_GEOMETRY_INPUT_TYPE 0x8917
+#define GL_GEOMETRY_OUTPUT_TYPE 0x8918
+#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1
+#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
+#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123
+#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124
+#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
+#define GL_CONTEXT_PROFILE_MASK 0x9126
+#define GL_DEPTH_CLAMP 0x864F
+#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C
+#define GL_FIRST_VERTEX_CONVENTION 0x8E4D
+#define GL_LAST_VERTEX_CONVENTION 0x8E4E
+#define GL_PROVOKING_VERTEX 0x8E4F
+#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
+#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
+#define GL_OBJECT_TYPE 0x9112
+#define GL_SYNC_CONDITION 0x9113
+#define GL_SYNC_STATUS 0x9114
+#define GL_SYNC_FLAGS 0x9115
+#define GL_SYNC_FENCE 0x9116
+#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
+#define GL_UNSIGNALED 0x9118
+#define GL_SIGNALED 0x9119
+#define GL_ALREADY_SIGNALED 0x911A
+#define GL_TIMEOUT_EXPIRED 0x911B
+#define GL_CONDITION_SATISFIED 0x911C
+#define GL_WAIT_FAILED 0x911D
+#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF
+#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
+#define GL_SAMPLE_POSITION 0x8E50
+#define GL_SAMPLE_MASK 0x8E51
+#define GL_SAMPLE_MASK_VALUE 0x8E52
+#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59
+#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
+#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101
+#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
+#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103
+#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104
+#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105
+#define GL_TEXTURE_SAMPLES 0x9106
+#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107
+#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
+#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
+#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B
+#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
+#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E
+#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F
+#define GL_MAX_INTEGER_SAMPLES 0x9110
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE
+#define GL_SRC1_COLOR 0x88F9
+#define GL_ONE_MINUS_SRC1_COLOR 0x88FA
+#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB
+#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC
+#define GL_ANY_SAMPLES_PASSED 0x8C2F
+#define GL_SAMPLER_BINDING 0x8919
+#define GL_RGB10_A2UI 0x906F
+#define GL_TEXTURE_SWIZZLE_R 0x8E42
+#define GL_TEXTURE_SWIZZLE_G 0x8E43
+#define GL_TEXTURE_SWIZZLE_B 0x8E44
+#define GL_TEXTURE_SWIZZLE_A 0x8E45
+#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
+#define GL_TIME_ELAPSED 0x88BF
+#define GL_TIMESTAMP 0x8E28
+#define GL_INT_2_10_10_10_REV 0x8D9F
+#ifndef GL_VERSION_1_0
+#define GL_VERSION_1_0 1
+GLAPI int GLAD_GL_VERSION_1_0;
+typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode);
+GLAPI PFNGLCULLFACEPROC glad_glCullFace;
+#define glCullFace glad_glCullFace
+typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode);
+GLAPI PFNGLFRONTFACEPROC glad_glFrontFace;
+#define glFrontFace glad_glFrontFace
+typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode);
+GLAPI PFNGLHINTPROC glad_glHint;
+#define glHint glad_glHint
+typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width);
+GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth;
+#define glLineWidth glad_glLineWidth
+typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size);
+GLAPI PFNGLPOINTSIZEPROC glad_glPointSize;
+#define glPointSize glad_glPointSize
+typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode);
+GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode;
+#define glPolygonMode glad_glPolygonMode
+typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI PFNGLSCISSORPROC glad_glScissor;
+#define glScissor glad_glScissor
+typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param);
+GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf;
+#define glTexParameterf glad_glTexParameterf
+typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat* params);
+GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv;
+#define glTexParameterfv glad_glTexParameterfv
+typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);
+GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri;
+#define glTexParameteri glad_glTexParameteri
+typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint* params);
+GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv;
+#define glTexParameteriv glad_glTexParameteriv
+typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void* pixels);
+GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D;
+#define glTexImage1D glad_glTexImage1D
+typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels);
+GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D;
+#define glTexImage2D glad_glTexImage2D
+typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf);
+GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer;
+#define glDrawBuffer glad_glDrawBuffer
+typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask);
+GLAPI PFNGLCLEARPROC glad_glClear;
+#define glClear glad_glClear
+typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GLAPI PFNGLCLEARCOLORPROC glad_glClearColor;
+#define glClearColor glad_glClearColor
+typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s);
+GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil;
+#define glClearStencil glad_glClearStencil
+typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth);
+GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth;
+#define glClearDepth glad_glClearDepth
+typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask);
+GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask;
+#define glStencilMask glad_glStencilMask
+typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GLAPI PFNGLCOLORMASKPROC glad_glColorMask;
+#define glColorMask glad_glColorMask
+typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag);
+GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask;
+#define glDepthMask glad_glDepthMask
+typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap);
+GLAPI PFNGLDISABLEPROC glad_glDisable;
+#define glDisable glad_glDisable
+typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap);
+GLAPI PFNGLENABLEPROC glad_glEnable;
+#define glEnable glad_glEnable
+typedef void (APIENTRYP PFNGLFINISHPROC)();
+GLAPI PFNGLFINISHPROC glad_glFinish;
+#define glFinish glad_glFinish
+typedef void (APIENTRYP PFNGLFLUSHPROC)();
+GLAPI PFNGLFLUSHPROC glad_glFlush;
+#define glFlush glad_glFlush
+typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor);
+GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc;
+#define glBlendFunc glad_glBlendFunc
+typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode);
+GLAPI PFNGLLOGICOPPROC glad_glLogicOp;
+#define glLogicOp glad_glLogicOp
+typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask);
+GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc;
+#define glStencilFunc glad_glStencilFunc
+typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass);
+GLAPI PFNGLSTENCILOPPROC glad_glStencilOp;
+#define glStencilOp glad_glStencilOp
+typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func);
+GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc;
+#define glDepthFunc glad_glDepthFunc
+typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param);
+GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref;
+#define glPixelStoref glad_glPixelStoref
+typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param);
+GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei;
+#define glPixelStorei glad_glPixelStorei
+typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src);
+GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer;
+#define glReadBuffer glad_glReadBuffer
+typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
+GLAPI PFNGLREADPIXELSPROC glad_glReadPixels;
+#define glReadPixels glad_glReadPixels
+typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean* data);
+GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv;
+#define glGetBooleanv glad_glGetBooleanv
+typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble* data);
+GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev;
+#define glGetDoublev glad_glGetDoublev
+typedef GLenum (APIENTRYP PFNGLGETERRORPROC)();
+GLAPI PFNGLGETERRORPROC glad_glGetError;
+#define glGetError glad_glGetError
+typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat* data);
+GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv;
+#define glGetFloatv glad_glGetFloatv
+typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint* data);
+GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv;
+#define glGetIntegerv glad_glGetIntegerv
+typedef const GLubyte* (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name);
+GLAPI PFNGLGETSTRINGPROC glad_glGetString;
+#define glGetString glad_glGetString
+typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void* pixels);
+GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage;
+#define glGetTexImage glad_glGetTexImage
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat* params);
+GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv;
+#define glGetTexParameterfv glad_glGetTexParameterfv
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params);
+GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv;
+#define glGetTexParameteriv glad_glGetTexParameteriv
+typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat* params);
+GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv;
+#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv
+typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint* params);
+GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv;
+#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv
+typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap);
+GLAPI PFNGLISENABLEDPROC glad_glIsEnabled;
+#define glIsEnabled glad_glIsEnabled
+typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble near, GLdouble far);
+GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange;
+#define glDepthRange glad_glDepthRange
+typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI PFNGLVIEWPORTPROC glad_glViewport;
+#define glViewport glad_glViewport
+#endif
+#ifndef GL_VERSION_1_1
+#define GL_VERSION_1_1 1
+GLAPI int GLAD_GL_VERSION_1_1;
+typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count);
+GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays;
+#define glDrawArrays glad_glDrawArrays
+typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices);
+GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements;
+#define glDrawElements glad_glDrawElements
+typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units);
+GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset;
+#define glPolygonOffset glad_glPolygonOffset
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D;
+#define glCopyTexImage1D glad_glCopyTexImage1D
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D;
+#define glCopyTexImage2D glad_glCopyTexImage2D
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D;
+#define glCopyTexSubImage1D glad_glCopyTexSubImage1D
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D;
+#define glCopyTexSubImage2D glad_glCopyTexSubImage2D
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels);
+GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D;
+#define glTexSubImage1D glad_glTexSubImage1D
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels);
+GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D;
+#define glTexSubImage2D glad_glTexSubImage2D
+typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture);
+GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture;
+#define glBindTexture glad_glBindTexture
+typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint* textures);
+GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures;
+#define glDeleteTextures glad_glDeleteTextures
+typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint* textures);
+GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures;
+#define glGenTextures glad_glGenTextures
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture);
+GLAPI PFNGLISTEXTUREPROC glad_glIsTexture;
+#define glIsTexture glad_glIsTexture
+#endif
+#ifndef GL_VERSION_1_2
+#define GL_VERSION_1_2 1
+GLAPI int GLAD_GL_VERSION_1_2;
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
+GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements;
+#define glDrawRangeElements glad_glDrawRangeElements
+typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels);
+GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D;
+#define glTexImage3D glad_glTexImage3D
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels);
+GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D;
+#define glTexSubImage3D glad_glTexSubImage3D
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D;
+#define glCopyTexSubImage3D glad_glCopyTexSubImage3D
+#endif
+#ifndef GL_VERSION_1_3
+#define GL_VERSION_1_3 1
+GLAPI int GLAD_GL_VERSION_1_3;
+typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture);
+GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture;
+#define glActiveTexture glad_glActiveTexture
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert);
+GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage;
+#define glSampleCoverage glad_glSampleCoverage
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data);
+GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D;
+#define glCompressedTexImage3D glad_glCompressedTexImage3D
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data);
+GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D;
+#define glCompressedTexImage2D glad_glCompressedTexImage2D
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void* data);
+GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D;
+#define glCompressedTexImage1D glad_glCompressedTexImage1D
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data);
+GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D;
+#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data);
+GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D;
+#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data);
+GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D;
+#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void* img);
+GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage;
+#define glGetCompressedTexImage glad_glGetCompressedTexImage
+#endif
+#ifndef GL_VERSION_1_4
+#define GL_VERSION_1_4 1
+GLAPI int GLAD_GL_VERSION_1_4;
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate;
+#define glBlendFuncSeparate glad_glBlendFuncSeparate
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount);
+GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays;
+#define glMultiDrawArrays glad_glMultiDrawArrays
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei* count, GLenum type, const void** indices, GLsizei drawcount);
+GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements;
+#define glMultiDrawElements glad_glMultiDrawElements
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param);
+GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf;
+#define glPointParameterf glad_glPointParameterf
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat* params);
+GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv;
+#define glPointParameterfv glad_glPointParameterfv
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param);
+GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri;
+#define glPointParameteri glad_glPointParameteri
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint* params);
+GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv;
+#define glPointParameteriv glad_glPointParameteriv
+typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor;
+#define glBlendColor glad_glBlendColor
+typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode);
+GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation;
+#define glBlendEquation glad_glBlendEquation
+#endif
+#ifndef GL_VERSION_1_5
+#define GL_VERSION_1_5 1
+GLAPI int GLAD_GL_VERSION_1_5;
+typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint* ids);
+GLAPI PFNGLGENQUERIESPROC glad_glGenQueries;
+#define glGenQueries glad_glGenQueries
+typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint* ids);
+GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries;
+#define glDeleteQueries glad_glDeleteQueries
+typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id);
+GLAPI PFNGLISQUERYPROC glad_glIsQuery;
+#define glIsQuery glad_glIsQuery
+typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id);
+GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery;
+#define glBeginQuery glad_glBeginQuery
+typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target);
+GLAPI PFNGLENDQUERYPROC glad_glEndQuery;
+#define glEndQuery glad_glEndQuery
+typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint* params);
+GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv;
+#define glGetQueryiv glad_glGetQueryiv
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint* params);
+GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv;
+#define glGetQueryObjectiv glad_glGetQueryObjectiv
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint* params);
+GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv;
+#define glGetQueryObjectuiv glad_glGetQueryObjectuiv
+typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer);
+GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer;
+#define glBindBuffer glad_glBindBuffer
+typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint* buffers);
+GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;
+#define glDeleteBuffers glad_glDeleteBuffers
+typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint* buffers);
+GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers;
+#define glGenBuffers glad_glGenBuffers
+typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer);
+GLAPI PFNGLISBUFFERPROC glad_glIsBuffer;
+#define glIsBuffer glad_glIsBuffer
+typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
+GLAPI PFNGLBUFFERDATAPROC glad_glBufferData;
+#define glBufferData glad_glBufferData
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
+GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData;
+#define glBufferSubData glad_glBufferSubData
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void* data);
+GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData;
+#define glGetBufferSubData glad_glGetBufferSubData
+typedef void* (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access);
+GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer;
+#define glMapBuffer glad_glMapBuffer
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target);
+GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer;
+#define glUnmapBuffer glad_glUnmapBuffer
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params);
+GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv;
+#define glGetBufferParameteriv glad_glGetBufferParameteriv
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void** params);
+GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv;
+#define glGetBufferPointerv glad_glGetBufferPointerv
+#endif
+#ifndef GL_VERSION_2_0
+#define GL_VERSION_2_0 1
+GLAPI int GLAD_GL_VERSION_2_0;
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha);
+GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate;
+#define glBlendEquationSeparate glad_glBlendEquationSeparate
+typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum* bufs);
+GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers;
+#define glDrawBuffers glad_glDrawBuffers
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate;
+#define glStencilOpSeparate glad_glStencilOpSeparate
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask);
+GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate;
+#define glStencilFuncSeparate glad_glStencilFuncSeparate
+typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask);
+GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate;
+#define glStencilMaskSeparate glad_glStencilMaskSeparate
+typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader);
+GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader;
+#define glAttachShader glad_glAttachShader
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar* name);
+GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation;
+#define glBindAttribLocation glad_glBindAttribLocation
+typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader);
+GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader;
+#define glCompileShader glad_glCompileShader
+typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)();
+GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram;
+#define glCreateProgram glad_glCreateProgram
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type);
+GLAPI PFNGLCREATESHADERPROC glad_glCreateShader;
+#define glCreateShader glad_glCreateShader
+typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program);
+GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram;
+#define glDeleteProgram glad_glDeleteProgram
+typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader);
+GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader;
+#define glDeleteShader glad_glDeleteShader
+typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader);
+GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader;
+#define glDetachShader glad_glDetachShader
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index);
+GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray;
+#define glDisableVertexAttribArray glad_glDisableVertexAttribArray
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index);
+GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray;
+#define glEnableVertexAttribArray glad_glEnableVertexAttribArray
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib;
+#define glGetActiveAttrib glad_glGetActiveAttrib
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform;
+#define glGetActiveUniform glad_glGetActiveUniform
+typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders);
+GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders;
+#define glGetAttachedShaders glad_glGetAttachedShaders
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar* name);
+GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation;
+#define glGetAttribLocation glad_glGetAttribLocation
+typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint* params);
+GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv;
+#define glGetProgramiv glad_glGetProgramiv
+typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
+GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog;
+#define glGetProgramInfoLog glad_glGetProgramInfoLog
+typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint* params);
+GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv;
+#define glGetShaderiv glad_glGetShaderiv
+typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
+GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog;
+#define glGetShaderInfoLog glad_glGetShaderInfoLog
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source);
+GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource;
+#define glGetShaderSource glad_glGetShaderSource
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar* name);
+GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation;
+#define glGetUniformLocation glad_glGetUniformLocation
+typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat* params);
+GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv;
+#define glGetUniformfv glad_glGetUniformfv
+typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint* params);
+GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv;
+#define glGetUniformiv glad_glGetUniformiv
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble* params);
+GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv;
+#define glGetVertexAttribdv glad_glGetVertexAttribdv
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat* params);
+GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv;
+#define glGetVertexAttribfv glad_glGetVertexAttribfv
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint* params);
+GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv;
+#define glGetVertexAttribiv glad_glGetVertexAttribiv
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void** pointer);
+GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv;
+#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program);
+GLAPI PFNGLISPROGRAMPROC glad_glIsProgram;
+#define glIsProgram glad_glIsProgram
+typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader);
+GLAPI PFNGLISSHADERPROC glad_glIsShader;
+#define glIsShader glad_glIsShader
+typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program);
+GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram;
+#define glLinkProgram glad_glLinkProgram
+typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar** string, const GLint* length);
+GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource;
+#define glShaderSource glad_glShaderSource
+typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program);
+GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram;
+#define glUseProgram glad_glUseProgram
+typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0);
+GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f;
+#define glUniform1f glad_glUniform1f
+typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1);
+GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f;
+#define glUniform2f glad_glUniform2f
+typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f;
+#define glUniform3f glad_glUniform3f
+typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f;
+#define glUniform4f glad_glUniform4f
+typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0);
+GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i;
+#define glUniform1i glad_glUniform1i
+typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1);
+GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i;
+#define glUniform2i glad_glUniform2i
+typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2);
+GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i;
+#define glUniform3i glad_glUniform3i
+typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i;
+#define glUniform4i glad_glUniform4i
+typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat* value);
+GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv;
+#define glUniform1fv glad_glUniform1fv
+typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat* value);
+GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv;
+#define glUniform2fv glad_glUniform2fv
+typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat* value);
+GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv;
+#define glUniform3fv glad_glUniform3fv
+typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat* value);
+GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv;
+#define glUniform4fv glad_glUniform4fv
+typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint* value);
+GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv;
+#define glUniform1iv glad_glUniform1iv
+typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint* value);
+GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv;
+#define glUniform2iv glad_glUniform2iv
+typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint* value);
+GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv;
+#define glUniform3iv glad_glUniform3iv
+typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint* value);
+GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv;
+#define glUniform4iv glad_glUniform4iv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv;
+#define glUniformMatrix2fv glad_glUniformMatrix2fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv;
+#define glUniformMatrix3fv glad_glUniformMatrix3fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv;
+#define glUniformMatrix4fv glad_glUniformMatrix4fv
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program);
+GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram;
+#define glValidateProgram glad_glValidateProgram
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x);
+GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d;
+#define glVertexAttrib1d glad_glVertexAttrib1d
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble* v);
+GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv;
+#define glVertexAttrib1dv glad_glVertexAttrib1dv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x);
+GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f;
+#define glVertexAttrib1f glad_glVertexAttrib1f
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat* v);
+GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv;
+#define glVertexAttrib1fv glad_glVertexAttrib1fv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x);
+GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s;
+#define glVertexAttrib1s glad_glVertexAttrib1s
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort* v);
+GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv;
+#define glVertexAttrib1sv glad_glVertexAttrib1sv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y);
+GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d;
+#define glVertexAttrib2d glad_glVertexAttrib2d
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble* v);
+GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv;
+#define glVertexAttrib2dv glad_glVertexAttrib2dv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y);
+GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f;
+#define glVertexAttrib2f glad_glVertexAttrib2f
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat* v);
+GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv;
+#define glVertexAttrib2fv glad_glVertexAttrib2fv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y);
+GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s;
+#define glVertexAttrib2s glad_glVertexAttrib2s
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort* v);
+GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv;
+#define glVertexAttrib2sv glad_glVertexAttrib2sv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d;
+#define glVertexAttrib3d glad_glVertexAttrib3d
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble* v);
+GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv;
+#define glVertexAttrib3dv glad_glVertexAttrib3dv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z);
+GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f;
+#define glVertexAttrib3f glad_glVertexAttrib3f
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat* v);
+GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv;
+#define glVertexAttrib3fv glad_glVertexAttrib3fv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z);
+GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s;
+#define glVertexAttrib3s glad_glVertexAttrib3s
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort* v);
+GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv;
+#define glVertexAttrib3sv glad_glVertexAttrib3sv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte* v);
+GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv;
+#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint* v);
+GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv;
+#define glVertexAttrib4Niv glad_glVertexAttrib4Niv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort* v);
+GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv;
+#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub;
+#define glVertexAttrib4Nub glad_glVertexAttrib4Nub
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte* v);
+GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv;
+#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint* v);
+GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv;
+#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort* v);
+GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv;
+#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte* v);
+GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv;
+#define glVertexAttrib4bv glad_glVertexAttrib4bv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d;
+#define glVertexAttrib4d glad_glVertexAttrib4d
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble* v);
+GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv;
+#define glVertexAttrib4dv glad_glVertexAttrib4dv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f;
+#define glVertexAttrib4f glad_glVertexAttrib4f
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat* v);
+GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv;
+#define glVertexAttrib4fv glad_glVertexAttrib4fv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint* v);
+GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv;
+#define glVertexAttrib4iv glad_glVertexAttrib4iv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s;
+#define glVertexAttrib4s glad_glVertexAttrib4s
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort* v);
+GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv;
+#define glVertexAttrib4sv glad_glVertexAttrib4sv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte* v);
+GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv;
+#define glVertexAttrib4ubv glad_glVertexAttrib4ubv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint* v);
+GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv;
+#define glVertexAttrib4uiv glad_glVertexAttrib4uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort* v);
+GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv;
+#define glVertexAttrib4usv glad_glVertexAttrib4usv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
+GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer;
+#define glVertexAttribPointer glad_glVertexAttribPointer
+#endif
+#ifndef GL_VERSION_2_1
+#define GL_VERSION_2_1 1
+GLAPI int GLAD_GL_VERSION_2_1;
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv;
+#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv;
+#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv;
+#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv;
+#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv;
+#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv;
+#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv
+#endif
+#ifndef GL_VERSION_3_0
+#define GL_VERSION_3_0 1
+GLAPI int GLAD_GL_VERSION_3_0;
+typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski;
+#define glColorMaski glad_glColorMaski
+typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean* data);
+GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v;
+#define glGetBooleani_v glad_glGetBooleani_v
+typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint* data);
+GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v;
+#define glGetIntegeri_v glad_glGetIntegeri_v
+typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index);
+GLAPI PFNGLENABLEIPROC glad_glEnablei;
+#define glEnablei glad_glEnablei
+typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index);
+GLAPI PFNGLDISABLEIPROC glad_glDisablei;
+#define glDisablei glad_glDisablei
+typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index);
+GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi;
+#define glIsEnabledi glad_glIsEnabledi
+typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode);
+GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback;
+#define glBeginTransformFeedback glad_glBeginTransformFeedback
+typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)();
+GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback;
+#define glEndTransformFeedback glad_glEndTransformFeedback
+typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange;
+#define glBindBufferRange glad_glBindBufferRange
+typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer);
+GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase;
+#define glBindBufferBase glad_glBindBufferBase
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar** varyings, GLenum bufferMode);
+GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings;
+#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name);
+GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying;
+#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying
+typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp);
+GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor;
+#define glClampColor glad_glClampColor
+typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode);
+GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender;
+#define glBeginConditionalRender glad_glBeginConditionalRender
+typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)();
+GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender;
+#define glEndConditionalRender glad_glEndConditionalRender
+typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer);
+GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer;
+#define glVertexAttribIPointer glad_glVertexAttribIPointer
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint* params);
+GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv;
+#define glGetVertexAttribIiv glad_glGetVertexAttribIiv
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint* params);
+GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv;
+#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x);
+GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i;
+#define glVertexAttribI1i glad_glVertexAttribI1i
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y);
+GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i;
+#define glVertexAttribI2i glad_glVertexAttribI2i
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z);
+GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i;
+#define glVertexAttribI3i glad_glVertexAttribI3i
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w);
+GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i;
+#define glVertexAttribI4i glad_glVertexAttribI4i
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x);
+GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui;
+#define glVertexAttribI1ui glad_glVertexAttribI1ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y);
+GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui;
+#define glVertexAttribI2ui glad_glVertexAttribI2ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z);
+GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui;
+#define glVertexAttribI3ui glad_glVertexAttribI3ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui;
+#define glVertexAttribI4ui glad_glVertexAttribI4ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint* v);
+GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv;
+#define glVertexAttribI1iv glad_glVertexAttribI1iv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint* v);
+GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv;
+#define glVertexAttribI2iv glad_glVertexAttribI2iv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint* v);
+GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv;
+#define glVertexAttribI3iv glad_glVertexAttribI3iv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint* v);
+GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv;
+#define glVertexAttribI4iv glad_glVertexAttribI4iv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint* v);
+GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv;
+#define glVertexAttribI1uiv glad_glVertexAttribI1uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint* v);
+GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv;
+#define glVertexAttribI2uiv glad_glVertexAttribI2uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint* v);
+GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv;
+#define glVertexAttribI3uiv glad_glVertexAttribI3uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint* v);
+GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv;
+#define glVertexAttribI4uiv glad_glVertexAttribI4uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte* v);
+GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv;
+#define glVertexAttribI4bv glad_glVertexAttribI4bv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort* v);
+GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv;
+#define glVertexAttribI4sv glad_glVertexAttribI4sv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte* v);
+GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv;
+#define glVertexAttribI4ubv glad_glVertexAttribI4ubv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort* v);
+GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv;
+#define glVertexAttribI4usv glad_glVertexAttribI4usv
+typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint* params);
+GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv;
+#define glGetUniformuiv glad_glGetUniformuiv
+typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar* name);
+GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation;
+#define glBindFragDataLocation glad_glBindFragDataLocation
+typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar* name);
+GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation;
+#define glGetFragDataLocation glad_glGetFragDataLocation
+typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0);
+GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui;
+#define glUniform1ui glad_glUniform1ui
+typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1);
+GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui;
+#define glUniform2ui glad_glUniform2ui
+typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2);
+GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui;
+#define glUniform3ui glad_glUniform3ui
+typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui;
+#define glUniform4ui glad_glUniform4ui
+typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint* value);
+GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv;
+#define glUniform1uiv glad_glUniform1uiv
+typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint* value);
+GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv;
+#define glUniform2uiv glad_glUniform2uiv
+typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint* value);
+GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv;
+#define glUniform3uiv glad_glUniform3uiv
+typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint* value);
+GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv;
+#define glUniform4uiv glad_glUniform4uiv
+typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint* params);
+GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv;
+#define glTexParameterIiv glad_glTexParameterIiv
+typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint* params);
+GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv;
+#define glTexParameterIuiv glad_glTexParameterIuiv
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint* params);
+GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv;
+#define glGetTexParameterIiv glad_glGetTexParameterIiv
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint* params);
+GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv;
+#define glGetTexParameterIuiv glad_glGetTexParameterIuiv
+typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint* value);
+GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv;
+#define glClearBufferiv glad_glClearBufferiv
+typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint* value);
+GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv;
+#define glClearBufferuiv glad_glClearBufferuiv
+typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat* value);
+GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv;
+#define glClearBufferfv glad_glClearBufferfv
+typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi;
+#define glClearBufferfi glad_glClearBufferfi
+typedef const GLubyte* (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index);
+GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi;
+#define glGetStringi glad_glGetStringi
+typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer);
+GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer;
+#define glIsRenderbuffer glad_glIsRenderbuffer
+typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer);
+GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer;
+#define glBindRenderbuffer glad_glBindRenderbuffer
+typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint* renderbuffers);
+GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers;
+#define glDeleteRenderbuffers glad_glDeleteRenderbuffers
+typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint* renderbuffers);
+GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers;
+#define glGenRenderbuffers glad_glGenRenderbuffers
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage;
+#define glRenderbufferStorage glad_glRenderbufferStorage
+typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params);
+GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv;
+#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv
+typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer);
+GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer;
+#define glIsFramebuffer glad_glIsFramebuffer
+typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer);
+GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer;
+#define glBindFramebuffer glad_glBindFramebuffer
+typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint* framebuffers);
+GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers;
+#define glDeleteFramebuffers glad_glDeleteFramebuffers
+typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint* framebuffers);
+GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers;
+#define glGenFramebuffers glad_glGenFramebuffers
+typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target);
+GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus;
+#define glCheckFramebufferStatus glad_glCheckFramebufferStatus
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D;
+#define glFramebufferTexture1D glad_glFramebufferTexture1D
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D;
+#define glFramebufferTexture2D glad_glFramebufferTexture2D
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D;
+#define glFramebufferTexture3D glad_glFramebufferTexture3D
+typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer;
+#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv;
+#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv
+typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target);
+GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap;
+#define glGenerateMipmap glad_glGenerateMipmap
+typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer;
+#define glBlitFramebuffer glad_glBlitFramebuffer
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample;
+#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer;
+#define glFramebufferTextureLayer glad_glFramebufferTextureLayer
+typedef void* (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange;
+#define glMapBufferRange glad_glMapBufferRange
+typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length);
+GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange;
+#define glFlushMappedBufferRange glad_glFlushMappedBufferRange
+typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array);
+GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray;
+#define glBindVertexArray glad_glBindVertexArray
+typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint* arrays);
+GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays;
+#define glDeleteVertexArrays glad_glDeleteVertexArrays
+typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint* arrays);
+GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays;
+#define glGenVertexArrays glad_glGenVertexArrays
+typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array);
+GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray;
+#define glIsVertexArray glad_glIsVertexArray
+#endif
+#ifndef GL_VERSION_3_1
+#define GL_VERSION_3_1 1
+GLAPI int GLAD_GL_VERSION_3_1;
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
+GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced;
+#define glDrawArraysInstanced glad_glDrawArraysInstanced
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount);
+GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced;
+#define glDrawElementsInstanced glad_glDrawElementsInstanced
+typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer);
+GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer;
+#define glTexBuffer glad_glTexBuffer
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index);
+GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex;
+#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex
+typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData;
+#define glCopyBufferSubData glad_glCopyBufferSubData
+typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar** uniformNames, GLuint* uniformIndices);
+GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices;
+#define glGetUniformIndices glad_glGetUniformIndices
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params);
+GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv;
+#define glGetActiveUniformsiv glad_glGetActiveUniformsiv
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName);
+GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName;
+#define glGetActiveUniformName glad_glGetActiveUniformName
+typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar* uniformBlockName);
+GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex;
+#define glGetUniformBlockIndex glad_glGetUniformBlockIndex
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params);
+GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv;
+#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName);
+GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName;
+#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName
+typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
+GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding;
+#define glUniformBlockBinding glad_glUniformBlockBinding
+#endif
+#ifndef GL_VERSION_3_2
+#define GL_VERSION_3_2 1
+GLAPI int GLAD_GL_VERSION_3_2;
+typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex);
+GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex;
+#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices, GLint basevertex);
+GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex;
+#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, GLint basevertex);
+GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex;
+#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei* count, GLenum type, const void** indices, GLsizei drawcount, const GLint* basevertex);
+GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex;
+#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex
+typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode);
+GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex;
+#define glProvokingVertex glad_glProvokingVertex
+typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags);
+GLAPI PFNGLFENCESYNCPROC glad_glFenceSync;
+#define glFenceSync glad_glFenceSync
+typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync);
+GLAPI PFNGLISSYNCPROC glad_glIsSync;
+#define glIsSync glad_glIsSync
+typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync);
+GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync;
+#define glDeleteSync glad_glDeleteSync
+typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);
+GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync;
+#define glClientWaitSync glad_glClientWaitSync
+typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);
+GLAPI PFNGLWAITSYNCPROC glad_glWaitSync;
+#define glWaitSync glad_glWaitSync
+typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64* data);
+GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v;
+#define glGetInteger64v glad_glGetInteger64v
+typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values);
+GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv;
+#define glGetSynciv glad_glGetSynciv
+typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64* data);
+GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v;
+#define glGetInteger64i_v glad_glGetInteger64i_v
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64* params);
+GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v;
+#define glGetBufferParameteri64v glad_glGetBufferParameteri64v
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level);
+GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture;
+#define glFramebufferTexture glad_glFramebufferTexture
+typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample;
+#define glTexImage2DMultisample glad_glTexImage2DMultisample
+typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample;
+#define glTexImage3DMultisample glad_glTexImage3DMultisample
+typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat* val);
+GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv;
+#define glGetMultisamplefv glad_glGetMultisamplefv
+typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask);
+GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski;
+#define glSampleMaski glad_glSampleMaski
+#endif
+#ifndef GL_VERSION_3_3
+#define GL_VERSION_3_3 1
+GLAPI int GLAD_GL_VERSION_3_3;
+typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar* name);
+GLAPI PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed;
+#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed
+typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar* name);
+GLAPI PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex;
+#define glGetFragDataIndex glad_glGetFragDataIndex
+typedef void (APIENTRYP PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint* samplers);
+GLAPI PFNGLGENSAMPLERSPROC glad_glGenSamplers;
+#define glGenSamplers glad_glGenSamplers
+typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint* samplers);
+GLAPI PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers;
+#define glDeleteSamplers glad_glDeleteSamplers
+typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC)(GLuint sampler);
+GLAPI PFNGLISSAMPLERPROC glad_glIsSampler;
+#define glIsSampler glad_glIsSampler
+typedef void (APIENTRYP PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler);
+GLAPI PFNGLBINDSAMPLERPROC glad_glBindSampler;
+#define glBindSampler glad_glBindSampler
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param);
+GLAPI PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri;
+#define glSamplerParameteri glad_glSamplerParameteri
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint* param);
+GLAPI PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv;
+#define glSamplerParameteriv glad_glSamplerParameteriv
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param);
+GLAPI PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf;
+#define glSamplerParameterf glad_glSamplerParameterf
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat* param);
+GLAPI PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv;
+#define glSamplerParameterfv glad_glSamplerParameterfv
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint* param);
+GLAPI PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv;
+#define glSamplerParameterIiv glad_glSamplerParameterIiv
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint* param);
+GLAPI PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv;
+#define glSamplerParameterIuiv glad_glSamplerParameterIuiv
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint* params);
+GLAPI PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv;
+#define glGetSamplerParameteriv glad_glGetSamplerParameteriv
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint* params);
+GLAPI PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv;
+#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat* params);
+GLAPI PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv;
+#define glGetSamplerParameterfv glad_glGetSamplerParameterfv
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint* params);
+GLAPI PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv;
+#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv
+typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target);
+GLAPI PFNGLQUERYCOUNTERPROC glad_glQueryCounter;
+#define glQueryCounter glad_glQueryCounter
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64* params);
+GLAPI PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v;
+#define glGetQueryObjecti64v glad_glGetQueryObjecti64v
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64* params);
+GLAPI PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v;
+#define glGetQueryObjectui64v glad_glGetQueryObjectui64v
+typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor);
+GLAPI PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor;
+#define glVertexAttribDivisor glad_glVertexAttribDivisor
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui;
+#define glVertexAttribP1ui glad_glVertexAttribP1ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint* value);
+GLAPI PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv;
+#define glVertexAttribP1uiv glad_glVertexAttribP1uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui;
+#define glVertexAttribP2ui glad_glVertexAttribP2ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint* value);
+GLAPI PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv;
+#define glVertexAttribP2uiv glad_glVertexAttribP2uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui;
+#define glVertexAttribP3ui glad_glVertexAttribP3ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint* value);
+GLAPI PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv;
+#define glVertexAttribP3uiv glad_glVertexAttribP3uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui;
+#define glVertexAttribP4ui glad_glVertexAttribP4ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint* value);
+GLAPI PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv;
+#define glVertexAttribP4uiv glad_glVertexAttribP4uiv
+typedef void (APIENTRYP PFNGLVERTEXP2UIPROC)(GLenum type, GLuint value);
+GLAPI PFNGLVERTEXP2UIPROC glad_glVertexP2ui;
+#define glVertexP2ui glad_glVertexP2ui
+typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC)(GLenum type, const GLuint* value);
+GLAPI PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv;
+#define glVertexP2uiv glad_glVertexP2uiv
+typedef void (APIENTRYP PFNGLVERTEXP3UIPROC)(GLenum type, GLuint value);
+GLAPI PFNGLVERTEXP3UIPROC glad_glVertexP3ui;
+#define glVertexP3ui glad_glVertexP3ui
+typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC)(GLenum type, const GLuint* value);
+GLAPI PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv;
+#define glVertexP3uiv glad_glVertexP3uiv
+typedef void (APIENTRYP PFNGLVERTEXP4UIPROC)(GLenum type, GLuint value);
+GLAPI PFNGLVERTEXP4UIPROC glad_glVertexP4ui;
+#define glVertexP4ui glad_glVertexP4ui
+typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC)(GLenum type, const GLuint* value);
+GLAPI PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv;
+#define glVertexP4uiv glad_glVertexP4uiv
+typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC)(GLenum type, GLuint coords);
+GLAPI PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui;
+#define glTexCoordP1ui glad_glTexCoordP1ui
+typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC)(GLenum type, const GLuint* coords);
+GLAPI PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv;
+#define glTexCoordP1uiv glad_glTexCoordP1uiv
+typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC)(GLenum type, GLuint coords);
+GLAPI PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui;
+#define glTexCoordP2ui glad_glTexCoordP2ui
+typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC)(GLenum type, const GLuint* coords);
+GLAPI PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv;
+#define glTexCoordP2uiv glad_glTexCoordP2uiv
+typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC)(GLenum type, GLuint coords);
+GLAPI PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui;
+#define glTexCoordP3ui glad_glTexCoordP3ui
+typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC)(GLenum type, const GLuint* coords);
+GLAPI PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv;
+#define glTexCoordP3uiv glad_glTexCoordP3uiv
+typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC)(GLenum type, GLuint coords);
+GLAPI PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui;
+#define glTexCoordP4ui glad_glTexCoordP4ui
+typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC)(GLenum type, const GLuint* coords);
+GLAPI PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv;
+#define glTexCoordP4uiv glad_glTexCoordP4uiv
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC)(GLenum texture, GLenum type, GLuint coords);
+GLAPI PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui;
+#define glMultiTexCoordP1ui glad_glMultiTexCoordP1ui
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC)(GLenum texture, GLenum type, const GLuint* coords);
+GLAPI PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv;
+#define glMultiTexCoordP1uiv glad_glMultiTexCoordP1uiv
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC)(GLenum texture, GLenum type, GLuint coords);
+GLAPI PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui;
+#define glMultiTexCoordP2ui glad_glMultiTexCoordP2ui
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC)(GLenum texture, GLenum type, const GLuint* coords);
+GLAPI PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv;
+#define glMultiTexCoordP2uiv glad_glMultiTexCoordP2uiv
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC)(GLenum texture, GLenum type, GLuint coords);
+GLAPI PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui;
+#define glMultiTexCoordP3ui glad_glMultiTexCoordP3ui
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC)(GLenum texture, GLenum type, const GLuint* coords);
+GLAPI PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv;
+#define glMultiTexCoordP3uiv glad_glMultiTexCoordP3uiv
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC)(GLenum texture, GLenum type, GLuint coords);
+GLAPI PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui;
+#define glMultiTexCoordP4ui glad_glMultiTexCoordP4ui
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC)(GLenum texture, GLenum type, const GLuint* coords);
+GLAPI PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv;
+#define glMultiTexCoordP4uiv glad_glMultiTexCoordP4uiv
+typedef void (APIENTRYP PFNGLNORMALP3UIPROC)(GLenum type, GLuint coords);
+GLAPI PFNGLNORMALP3UIPROC glad_glNormalP3ui;
+#define glNormalP3ui glad_glNormalP3ui
+typedef void (APIENTRYP PFNGLNORMALP3UIVPROC)(GLenum type, const GLuint* coords);
+GLAPI PFNGLNORMALP3UIVPROC glad_glNormalP3uiv;
+#define glNormalP3uiv glad_glNormalP3uiv
+typedef void (APIENTRYP PFNGLCOLORP3UIPROC)(GLenum type, GLuint color);
+GLAPI PFNGLCOLORP3UIPROC glad_glColorP3ui;
+#define glColorP3ui glad_glColorP3ui
+typedef void (APIENTRYP PFNGLCOLORP3UIVPROC)(GLenum type, const GLuint* color);
+GLAPI PFNGLCOLORP3UIVPROC glad_glColorP3uiv;
+#define glColorP3uiv glad_glColorP3uiv
+typedef void (APIENTRYP PFNGLCOLORP4UIPROC)(GLenum type, GLuint color);
+GLAPI PFNGLCOLORP4UIPROC glad_glColorP4ui;
+#define glColorP4ui glad_glColorP4ui
+typedef void (APIENTRYP PFNGLCOLORP4UIVPROC)(GLenum type, const GLuint* color);
+GLAPI PFNGLCOLORP4UIVPROC glad_glColorP4uiv;
+#define glColorP4uiv glad_glColorP4uiv
+typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC)(GLenum type, GLuint color);
+GLAPI PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui;
+#define glSecondaryColorP3ui glad_glSecondaryColorP3ui
+typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint* color);
+GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
+#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv
+#endif
+#define GL_MAX_DEBUG_MESSAGE_LENGTH_AMD 0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD 0x9144
+#define GL_DEBUG_LOGGED_MESSAGES_AMD 0x9145
+#define GL_DEBUG_SEVERITY_HIGH_AMD 0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM_AMD 0x9147
+#define GL_DEBUG_SEVERITY_LOW_AMD 0x9148
+#define GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149
+#define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A
+#define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B
+#define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C
+#define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D
+#define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E
+#define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F
+#define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150
+#define GL_QUERY_BUFFER_AMD 0x9192
+#define GL_QUERY_BUFFER_BINDING_AMD 0x9193
+#define GL_QUERY_RESULT_NO_WAIT_AMD 0x9194
+#define GL_FIXED 0x140C
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+#define GL_SHADER_COMPILER 0x8DFA
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_RGB565 0x8D62
+#define GL_COMPRESSED_RGB8_ETC2 0x9274
+#define GL_COMPRESSED_SRGB8_ETC2 0x9275
+#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
+#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
+#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
+#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
+#define GL_COMPRESSED_R11_EAC 0x9270
+#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
+#define GL_COMPRESSED_RG11_EAC 0x9272
+#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
+#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
+#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A
+#define GL_MAX_ELEMENT_INDEX 0x8D6B
+#define GL_MAP_PERSISTENT_BIT 0x0040
+#define GL_MAP_COHERENT_BIT 0x0080
+#define GL_DYNAMIC_STORAGE_BIT 0x0100
+#define GL_CLIENT_STORAGE_BIT 0x0200
+#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000
+#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F
+#define GL_BUFFER_STORAGE_FLAGS 0x8220
+#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127
+#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128
+#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129
+#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A
+#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B
+#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C
+#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D
+#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E
+#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242
+#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243
+#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244
+#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245
+#define GL_DEBUG_SOURCE_API_ARB 0x8246
+#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247
+#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248
+#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249
+#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A
+#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B
+#define GL_DEBUG_TYPE_ERROR_ARB 0x824C
+#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D
+#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E
+#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F
+#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250
+#define GL_DEBUG_TYPE_OTHER_ARB 0x8251
+#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144
+#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145
+#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147
+#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148
+#define GL_DEPTH_COMPONENT16_ARB 0x81A5
+#define GL_DEPTH_COMPONENT24_ARB 0x81A6
+#define GL_DEPTH_COMPONENT32_ARB 0x81A7
+#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A
+#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B
+#define GL_MAX_DRAW_BUFFERS_ARB 0x8824
+#define GL_DRAW_BUFFER0_ARB 0x8825
+#define GL_DRAW_BUFFER1_ARB 0x8826
+#define GL_DRAW_BUFFER2_ARB 0x8827
+#define GL_DRAW_BUFFER3_ARB 0x8828
+#define GL_DRAW_BUFFER4_ARB 0x8829
+#define GL_DRAW_BUFFER5_ARB 0x882A
+#define GL_DRAW_BUFFER6_ARB 0x882B
+#define GL_DRAW_BUFFER7_ARB 0x882C
+#define GL_DRAW_BUFFER8_ARB 0x882D
+#define GL_DRAW_BUFFER9_ARB 0x882E
+#define GL_DRAW_BUFFER10_ARB 0x882F
+#define GL_DRAW_BUFFER11_ARB 0x8830
+#define GL_DRAW_BUFFER12_ARB 0x8831
+#define GL_DRAW_BUFFER13_ARB 0x8832
+#define GL_DRAW_BUFFER14_ARB 0x8833
+#define GL_DRAW_BUFFER15_ARB 0x8834
+#define GL_MAX_UNIFORM_LOCATIONS 0x826E
+#define GL_FRAGMENT_PROGRAM_ARB 0x8804
+#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875
+#define GL_PROGRAM_LENGTH_ARB 0x8627
+#define GL_PROGRAM_FORMAT_ARB 0x8876
+#define GL_PROGRAM_BINDING_ARB 0x8677
+#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0
+#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1
+#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2
+#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3
+#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4
+#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5
+#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6
+#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7
+#define GL_PROGRAM_PARAMETERS_ARB 0x88A8
+#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9
+#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA
+#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB
+#define GL_PROGRAM_ATTRIBS_ARB 0x88AC
+#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD
+#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE
+#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF
+#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4
+#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5
+#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6
+#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805
+#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806
+#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807
+#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808
+#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809
+#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A
+#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B
+#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C
+#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D
+#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E
+#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F
+#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810
+#define GL_PROGRAM_STRING_ARB 0x8628
+#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B
+#define GL_CURRENT_MATRIX_ARB 0x8641
+#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7
+#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640
+#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F
+#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E
+#define GL_MAX_TEXTURE_COORDS_ARB 0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872
+#define GL_PROGRAM_ERROR_STRING_ARB 0x8874
+#define GL_MATRIX0_ARB 0x88C0
+#define GL_MATRIX1_ARB 0x88C1
+#define GL_MATRIX2_ARB 0x88C2
+#define GL_MATRIX3_ARB 0x88C3
+#define GL_MATRIX4_ARB 0x88C4
+#define GL_MATRIX5_ARB 0x88C5
+#define GL_MATRIX6_ARB 0x88C6
+#define GL_MATRIX7_ARB 0x88C7
+#define GL_MATRIX8_ARB 0x88C8
+#define GL_MATRIX9_ARB 0x88C9
+#define GL_MATRIX10_ARB 0x88CA
+#define GL_MATRIX11_ARB 0x88CB
+#define GL_MATRIX12_ARB 0x88CC
+#define GL_MATRIX13_ARB 0x88CD
+#define GL_MATRIX14_ARB 0x88CE
+#define GL_MATRIX15_ARB 0x88CF
+#define GL_MATRIX16_ARB 0x88D0
+#define GL_MATRIX17_ARB 0x88D1
+#define GL_MATRIX18_ARB 0x88D2
+#define GL_MATRIX19_ARB 0x88D3
+#define GL_MATRIX20_ARB 0x88D4
+#define GL_MATRIX21_ARB 0x88D5
+#define GL_MATRIX22_ARB 0x88D6
+#define GL_MATRIX23_ARB 0x88D7
+#define GL_MATRIX24_ARB 0x88D8
+#define GL_MATRIX25_ARB 0x88D9
+#define GL_MATRIX26_ARB 0x88DA
+#define GL_MATRIX27_ARB 0x88DB
+#define GL_MATRIX28_ARB 0x88DC
+#define GL_MATRIX29_ARB 0x88DD
+#define GL_MATRIX30_ARB 0x88DE
+#define GL_MATRIX31_ARB 0x88DF
+#define GL_FRAGMENT_SHADER_ARB 0x8B30
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B
+#define GL_MULTISAMPLE_ARB 0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F
+#define GL_SAMPLE_COVERAGE_ARB 0x80A0
+#define GL_SAMPLE_BUFFERS_ARB 0x80A8
+#define GL_SAMPLES_ARB 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB
+#define GL_MULTISAMPLE_BIT_ARB 0x20000000
+#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB 0x933D
+#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB 0x933E
+#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB 0x933F
+#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB 0x9340
+#define GL_SAMPLE_LOCATION_ARB 0x8E50
+#define GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB 0x9341
+#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB 0x9342
+#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343
+#define GL_COMPRESSED_ALPHA_ARB 0x84E9
+#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB
+#define GL_COMPRESSED_INTENSITY_ARB 0x84EC
+#define GL_COMPRESSED_RGB_ARB 0x84ED
+#define GL_COMPRESSED_RGBA_ARB 0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0
+#define GL_TEXTURE_COMPRESSED_ARB 0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3
+#define GL_TEXTURE_RED_TYPE_ARB 0x8C10
+#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11
+#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12
+#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13
+#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14
+#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15
+#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16
+#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17
+#define GL_RGBA32F_ARB 0x8814
+#define GL_RGB32F_ARB 0x8815
+#define GL_ALPHA32F_ARB 0x8816
+#define GL_INTENSITY32F_ARB 0x8817
+#define GL_LUMINANCE32F_ARB 0x8818
+#define GL_LUMINANCE_ALPHA32F_ARB 0x8819
+#define GL_RGBA16F_ARB 0x881A
+#define GL_RGB16F_ARB 0x881B
+#define GL_ALPHA16F_ARB 0x881C
+#define GL_INTENSITY16F_ARB 0x881D
+#define GL_LUMINANCE16F_ARB 0x881E
+#define GL_LUMINANCE_ALPHA16F_ARB 0x881F
+#define GL_VERTEX_ATTRIB_BINDING 0x82D4
+#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5
+#define GL_VERTEX_BINDING_DIVISOR 0x82D6
+#define GL_VERTEX_BINDING_OFFSET 0x82D7
+#define GL_VERTEX_BINDING_STRIDE 0x82D8
+#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9
+#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA
+#define GL_BUFFER_SIZE_ARB 0x8764
+#define GL_BUFFER_USAGE_ARB 0x8765
+#define GL_ARRAY_BUFFER_ARB 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893
+#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
+#define GL_READ_ONLY_ARB 0x88B8
+#define GL_WRITE_ONLY_ARB 0x88B9
+#define GL_READ_WRITE_ARB 0x88BA
+#define GL_BUFFER_ACCESS_ARB 0x88BB
+#define GL_BUFFER_MAPPED_ARB 0x88BC
+#define GL_BUFFER_MAP_POINTER_ARB 0x88BD
+#define GL_STREAM_DRAW_ARB 0x88E0
+#define GL_STREAM_READ_ARB 0x88E1
+#define GL_STREAM_COPY_ARB 0x88E2
+#define GL_STATIC_DRAW_ARB 0x88E4
+#define GL_STATIC_READ_ARB 0x88E5
+#define GL_STATIC_COPY_ARB 0x88E6
+#define GL_DYNAMIC_DRAW_ARB 0x88E8
+#define GL_DYNAMIC_READ_ARB 0x88E9
+#define GL_DYNAMIC_COPY_ARB 0x88EA
+#define GL_COLOR_SUM_ARB 0x8458
+#define GL_VERTEX_PROGRAM_ARB 0x8620
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625
+#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626
+#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645
+#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A
+#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0
+#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1
+#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2
+#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3
+#define GL_VERTEX_SHADER_ARB 0x8B31
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A
+#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D
+#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89
+#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A
+#define GL_FLOAT_VEC2_ARB 0x8B50
+#define GL_FLOAT_VEC3_ARB 0x8B51
+#define GL_FLOAT_VEC4_ARB 0x8B52
+#define GL_FLOAT_MAT2_ARB 0x8B5A
+#define GL_FLOAT_MAT3_ARB 0x8B5B
+#define GL_FLOAT_MAT4_ARB 0x8B5C
+#define GL_ELEMENT_ARRAY_ATI 0x8768
+#define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769
+#define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A
+#define GL_FRAGMENT_SHADER_ATI 0x8920
+#define GL_REG_0_ATI 0x8921
+#define GL_REG_1_ATI 0x8922
+#define GL_REG_2_ATI 0x8923
+#define GL_REG_3_ATI 0x8924
+#define GL_REG_4_ATI 0x8925
+#define GL_REG_5_ATI 0x8926
+#define GL_REG_6_ATI 0x8927
+#define GL_REG_7_ATI 0x8928
+#define GL_REG_8_ATI 0x8929
+#define GL_REG_9_ATI 0x892A
+#define GL_REG_10_ATI 0x892B
+#define GL_REG_11_ATI 0x892C
+#define GL_REG_12_ATI 0x892D
+#define GL_REG_13_ATI 0x892E
+#define GL_REG_14_ATI 0x892F
+#define GL_REG_15_ATI 0x8930
+#define GL_REG_16_ATI 0x8931
+#define GL_REG_17_ATI 0x8932
+#define GL_REG_18_ATI 0x8933
+#define GL_REG_19_ATI 0x8934
+#define GL_REG_20_ATI 0x8935
+#define GL_REG_21_ATI 0x8936
+#define GL_REG_22_ATI 0x8937
+#define GL_REG_23_ATI 0x8938
+#define GL_REG_24_ATI 0x8939
+#define GL_REG_25_ATI 0x893A
+#define GL_REG_26_ATI 0x893B
+#define GL_REG_27_ATI 0x893C
+#define GL_REG_28_ATI 0x893D
+#define GL_REG_29_ATI 0x893E
+#define GL_REG_30_ATI 0x893F
+#define GL_REG_31_ATI 0x8940
+#define GL_CON_0_ATI 0x8941
+#define GL_CON_1_ATI 0x8942
+#define GL_CON_2_ATI 0x8943
+#define GL_CON_3_ATI 0x8944
+#define GL_CON_4_ATI 0x8945
+#define GL_CON_5_ATI 0x8946
+#define GL_CON_6_ATI 0x8947
+#define GL_CON_7_ATI 0x8948
+#define GL_CON_8_ATI 0x8949
+#define GL_CON_9_ATI 0x894A
+#define GL_CON_10_ATI 0x894B
+#define GL_CON_11_ATI 0x894C
+#define GL_CON_12_ATI 0x894D
+#define GL_CON_13_ATI 0x894E
+#define GL_CON_14_ATI 0x894F
+#define GL_CON_15_ATI 0x8950
+#define GL_CON_16_ATI 0x8951
+#define GL_CON_17_ATI 0x8952
+#define GL_CON_18_ATI 0x8953
+#define GL_CON_19_ATI 0x8954
+#define GL_CON_20_ATI 0x8955
+#define GL_CON_21_ATI 0x8956
+#define GL_CON_22_ATI 0x8957
+#define GL_CON_23_ATI 0x8958
+#define GL_CON_24_ATI 0x8959
+#define GL_CON_25_ATI 0x895A
+#define GL_CON_26_ATI 0x895B
+#define GL_CON_27_ATI 0x895C
+#define GL_CON_28_ATI 0x895D
+#define GL_CON_29_ATI 0x895E
+#define GL_CON_30_ATI 0x895F
+#define GL_CON_31_ATI 0x8960
+#define GL_MOV_ATI 0x8961
+#define GL_ADD_ATI 0x8963
+#define GL_MUL_ATI 0x8964
+#define GL_SUB_ATI 0x8965
+#define GL_DOT3_ATI 0x8966
+#define GL_DOT4_ATI 0x8967
+#define GL_MAD_ATI 0x8968
+#define GL_LERP_ATI 0x8969
+#define GL_CND_ATI 0x896A
+#define GL_CND0_ATI 0x896B
+#define GL_DOT2_ADD_ATI 0x896C
+#define GL_SECONDARY_INTERPOLATOR_ATI 0x896D
+#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E
+#define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F
+#define GL_NUM_PASSES_ATI 0x8970
+#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971
+#define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972
+#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973
+#define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974
+#define GL_COLOR_ALPHA_PAIRING_ATI 0x8975
+#define GL_SWIZZLE_STR_ATI 0x8976
+#define GL_SWIZZLE_STQ_ATI 0x8977
+#define GL_SWIZZLE_STR_DR_ATI 0x8978
+#define GL_SWIZZLE_STQ_DQ_ATI 0x8979
+#define GL_SWIZZLE_STRQ_ATI 0x897A
+#define GL_SWIZZLE_STRQ_DQ_ATI 0x897B
+#define GL_RED_BIT_ATI 0x00000001
+#define GL_GREEN_BIT_ATI 0x00000002
+#define GL_BLUE_BIT_ATI 0x00000004
+#define GL_2X_BIT_ATI 0x00000001
+#define GL_4X_BIT_ATI 0x00000002
+#define GL_8X_BIT_ATI 0x00000004
+#define GL_HALF_BIT_ATI 0x00000008
+#define GL_QUARTER_BIT_ATI 0x00000010
+#define GL_EIGHTH_BIT_ATI 0x00000020
+#define GL_SATURATE_BIT_ATI 0x00000040
+#define GL_COMP_BIT_ATI 0x00000002
+#define GL_NEGATE_BIT_ATI 0x00000004
+#define GL_BIAS_BIT_ATI 0x00000008
+#define GL_STATIC_ATI 0x8760
+#define GL_DYNAMIC_ATI 0x8761
+#define GL_PRESERVE_ATI 0x8762
+#define GL_DISCARD_ATI 0x8763
+#define GL_OBJECT_BUFFER_SIZE_ATI 0x8764
+#define GL_OBJECT_BUFFER_USAGE_ATI 0x8765
+#define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766
+#define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767
+#define GL_CONSTANT_COLOR_EXT 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002
+#define GL_CONSTANT_ALPHA_EXT 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004
+#define GL_BLEND_COLOR_EXT 0x8005
+#define GL_BLEND_EQUATION_RGB_EXT 0x8009
+#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D
+#define GL_BLEND_DST_RGB_EXT 0x80C8
+#define GL_BLEND_SRC_RGB_EXT 0x80C9
+#define GL_BLEND_DST_ALPHA_EXT 0x80CA
+#define GL_BLEND_SRC_ALPHA_EXT 0x80CB
+#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA
+#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
+#define GL_MAX_SAMPLES_EXT 0x8D57
+#define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA
+#define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB
+#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
+#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8
+#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6
+#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4
+#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD
+#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
+#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
+#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
+#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
+#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
+#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
+#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
+#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
+#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
+#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
+#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
+#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
+#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
+#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
+#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
+#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
+#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
+#define GL_DEPTH_ATTACHMENT_EXT 0x8D00
+#define GL_STENCIL_ATTACHMENT_EXT 0x8D20
+#define GL_FRAMEBUFFER_EXT 0x8D40
+#define GL_RENDERBUFFER_EXT 0x8D41
+#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42
+#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44
+#define GL_STENCIL_INDEX1_EXT 0x8D46
+#define GL_STENCIL_INDEX4_EXT 0x8D47
+#define GL_STENCIL_INDEX8_EXT 0x8D48
+#define GL_STENCIL_INDEX16_EXT 0x8D49
+#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
+#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9
+#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA
+#define GL_IUI_V2F_EXT 0x81AD
+#define GL_IUI_V3F_EXT 0x81AE
+#define GL_IUI_N3F_V2F_EXT 0x81AF
+#define GL_IUI_N3F_V3F_EXT 0x81B0
+#define GL_T2F_IUI_V2F_EXT 0x81B1
+#define GL_T2F_IUI_V3F_EXT 0x81B2
+#define GL_T2F_IUI_N3F_V2F_EXT 0x81B3
+#define GL_T2F_IUI_N3F_V3F_EXT 0x81B4
+#define GL_ALPHA4_EXT 0x803B
+#define GL_ALPHA8_EXT 0x803C
+#define GL_ALPHA12_EXT 0x803D
+#define GL_ALPHA16_EXT 0x803E
+#define GL_LUMINANCE4_EXT 0x803F
+#define GL_LUMINANCE8_EXT 0x8040
+#define GL_LUMINANCE12_EXT 0x8041
+#define GL_LUMINANCE16_EXT 0x8042
+#define GL_LUMINANCE4_ALPHA4_EXT 0x8043
+#define GL_LUMINANCE6_ALPHA2_EXT 0x8044
+#define GL_LUMINANCE8_ALPHA8_EXT 0x8045
+#define GL_LUMINANCE12_ALPHA4_EXT 0x8046
+#define GL_LUMINANCE12_ALPHA12_EXT 0x8047
+#define GL_LUMINANCE16_ALPHA16_EXT 0x8048
+#define GL_INTENSITY_EXT 0x8049
+#define GL_INTENSITY4_EXT 0x804A
+#define GL_INTENSITY8_EXT 0x804B
+#define GL_INTENSITY12_EXT 0x804C
+#define GL_INTENSITY16_EXT 0x804D
+#define GL_RGB2_EXT 0x804E
+#define GL_RGB4_EXT 0x804F
+#define GL_RGB5_EXT 0x8050
+#define GL_RGB8_EXT 0x8051
+#define GL_RGB10_EXT 0x8052
+#define GL_RGB12_EXT 0x8053
+#define GL_RGB16_EXT 0x8054
+#define GL_RGBA2_EXT 0x8055
+#define GL_RGBA4_EXT 0x8056
+#define GL_RGB5_A1_EXT 0x8057
+#define GL_RGBA8_EXT 0x8058
+#define GL_RGB10_A2_EXT 0x8059
+#define GL_RGBA12_EXT 0x805A
+#define GL_RGBA16_EXT 0x805B
+#define GL_TEXTURE_RED_SIZE_EXT 0x805C
+#define GL_TEXTURE_GREEN_SIZE_EXT 0x805D
+#define GL_TEXTURE_BLUE_SIZE_EXT 0x805E
+#define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F
+#define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060
+#define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061
+#define GL_REPLACE_EXT 0x8062
+#define GL_PROXY_TEXTURE_1D_EXT 0x8063
+#define GL_PROXY_TEXTURE_2D_EXT 0x8064
+#define GL_TEXTURE_TOO_LARGE_EXT 0x8065
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+#define GL_SRGB_EXT 0x8C40
+#define GL_SRGB8_EXT 0x8C41
+#define GL_SRGB_ALPHA_EXT 0x8C42
+#define GL_SRGB8_ALPHA8_EXT 0x8C43
+#define GL_SLUMINANCE_ALPHA_EXT 0x8C44
+#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45
+#define GL_SLUMINANCE_EXT 0x8C46
+#define GL_SLUMINANCE8_EXT 0x8C47
+#define GL_COMPRESSED_SRGB_EXT 0x8C48
+#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49
+#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A
+#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B
+#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F
+#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42
+#define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43
+#define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44
+#define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45
+#define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46
+#define GL_VERTEX_ARRAY_EXT 0x8074
+#define GL_NORMAL_ARRAY_EXT 0x8075
+#define GL_COLOR_ARRAY_EXT 0x8076
+#define GL_INDEX_ARRAY_EXT 0x8077
+#define GL_TEXTURE_COORD_ARRAY_EXT 0x8078
+#define GL_EDGE_FLAG_ARRAY_EXT 0x8079
+#define GL_VERTEX_ARRAY_SIZE_EXT 0x807A
+#define GL_VERTEX_ARRAY_TYPE_EXT 0x807B
+#define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C
+#define GL_VERTEX_ARRAY_COUNT_EXT 0x807D
+#define GL_NORMAL_ARRAY_TYPE_EXT 0x807E
+#define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F
+#define GL_NORMAL_ARRAY_COUNT_EXT 0x8080
+#define GL_COLOR_ARRAY_SIZE_EXT 0x8081
+#define GL_COLOR_ARRAY_TYPE_EXT 0x8082
+#define GL_COLOR_ARRAY_STRIDE_EXT 0x8083
+#define GL_COLOR_ARRAY_COUNT_EXT 0x8084
+#define GL_INDEX_ARRAY_TYPE_EXT 0x8085
+#define GL_INDEX_ARRAY_STRIDE_EXT 0x8086
+#define GL_INDEX_ARRAY_COUNT_EXT 0x8087
+#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A
+#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B
+#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C
+#define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D
+#define GL_VERTEX_ARRAY_POINTER_EXT 0x808E
+#define GL_NORMAL_ARRAY_POINTER_EXT 0x808F
+#define GL_COLOR_ARRAY_POINTER_EXT 0x8090
+#define GL_INDEX_ARRAY_POINTER_EXT 0x8091
+#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092
+#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093
+#define GL_VERTEX_SHADER_EXT 0x8780
+#define GL_VERTEX_SHADER_BINDING_EXT 0x8781
+#define GL_OP_INDEX_EXT 0x8782
+#define GL_OP_NEGATE_EXT 0x8783
+#define GL_OP_DOT3_EXT 0x8784
+#define GL_OP_DOT4_EXT 0x8785
+#define GL_OP_MUL_EXT 0x8786
+#define GL_OP_ADD_EXT 0x8787
+#define GL_OP_MADD_EXT 0x8788
+#define GL_OP_FRAC_EXT 0x8789
+#define GL_OP_MAX_EXT 0x878A
+#define GL_OP_MIN_EXT 0x878B
+#define GL_OP_SET_GE_EXT 0x878C
+#define GL_OP_SET_LT_EXT 0x878D
+#define GL_OP_CLAMP_EXT 0x878E
+#define GL_OP_FLOOR_EXT 0x878F
+#define GL_OP_ROUND_EXT 0x8790
+#define GL_OP_EXP_BASE_2_EXT 0x8791
+#define GL_OP_LOG_BASE_2_EXT 0x8792
+#define GL_OP_POWER_EXT 0x8793
+#define GL_OP_RECIP_EXT 0x8794
+#define GL_OP_RECIP_SQRT_EXT 0x8795
+#define GL_OP_SUB_EXT 0x8796
+#define GL_OP_CROSS_PRODUCT_EXT 0x8797
+#define GL_OP_MULTIPLY_MATRIX_EXT 0x8798
+#define GL_OP_MOV_EXT 0x8799
+#define GL_OUTPUT_VERTEX_EXT 0x879A
+#define GL_OUTPUT_COLOR0_EXT 0x879B
+#define GL_OUTPUT_COLOR1_EXT 0x879C
+#define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D
+#define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E
+#define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F
+#define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0
+#define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1
+#define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2
+#define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3
+#define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4
+#define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5
+#define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6
+#define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7
+#define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8
+#define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9
+#define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA
+#define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB
+#define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC
+#define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD
+#define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE
+#define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF
+#define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0
+#define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1
+#define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2
+#define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3
+#define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4
+#define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5
+#define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6
+#define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7
+#define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8
+#define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9
+#define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA
+#define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB
+#define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC
+#define GL_OUTPUT_FOG_EXT 0x87BD
+#define GL_SCALAR_EXT 0x87BE
+#define GL_VECTOR_EXT 0x87BF
+#define GL_MATRIX_EXT 0x87C0
+#define GL_VARIANT_EXT 0x87C1
+#define GL_INVARIANT_EXT 0x87C2
+#define GL_LOCAL_CONSTANT_EXT 0x87C3
+#define GL_LOCAL_EXT 0x87C4
+#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5
+#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6
+#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7
+#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8
+#define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE
+#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF
+#define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0
+#define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1
+#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2
+#define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3
+#define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4
+#define GL_X_EXT 0x87D5
+#define GL_Y_EXT 0x87D6
+#define GL_Z_EXT 0x87D7
+#define GL_W_EXT 0x87D8
+#define GL_NEGATIVE_X_EXT 0x87D9
+#define GL_NEGATIVE_Y_EXT 0x87DA
+#define GL_NEGATIVE_Z_EXT 0x87DB
+#define GL_NEGATIVE_W_EXT 0x87DC
+#define GL_ZERO_EXT 0x87DD
+#define GL_ONE_EXT 0x87DE
+#define GL_NEGATIVE_ONE_EXT 0x87DF
+#define GL_NORMALIZED_RANGE_EXT 0x87E0
+#define GL_FULL_RANGE_EXT 0x87E1
+#define GL_CURRENT_VERTEX_EXT 0x87E2
+#define GL_MVP_MATRIX_EXT 0x87E3
+#define GL_VARIANT_VALUE_EXT 0x87E4
+#define GL_VARIANT_DATATYPE_EXT 0x87E5
+#define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6
+#define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7
+#define GL_VARIANT_ARRAY_EXT 0x87E8
+#define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9
+#define GL_INVARIANT_VALUE_EXT 0x87EA
+#define GL_INVARIANT_DATATYPE_EXT 0x87EB
+#define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC
+#define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED
+#ifndef GL_AMD_debug_output
+#define GL_AMD_debug_output 1
+GLAPI int GLAD_GL_AMD_debug_output;
+typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC)(GLenum category, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled);
+GLAPI PFNGLDEBUGMESSAGEENABLEAMDPROC glad_glDebugMessageEnableAMD;
+#define glDebugMessageEnableAMD glad_glDebugMessageEnableAMD
+typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC)(GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar* buf);
+GLAPI PFNGLDEBUGMESSAGEINSERTAMDPROC glad_glDebugMessageInsertAMD;
+#define glDebugMessageInsertAMD glad_glDebugMessageInsertAMD
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC)(GLDEBUGPROCAMD callback, void* userParam);
+GLAPI PFNGLDEBUGMESSAGECALLBACKAMDPROC glad_glDebugMessageCallbackAMD;
+#define glDebugMessageCallbackAMD glad_glDebugMessageCallbackAMD
+typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC)(GLuint count, GLsizei bufsize, GLenum* categories, GLuint* severities, GLuint* ids, GLsizei* lengths, GLchar* message);
+GLAPI PFNGLGETDEBUGMESSAGELOGAMDPROC glad_glGetDebugMessageLogAMD;
+#define glGetDebugMessageLogAMD glad_glGetDebugMessageLogAMD
+#endif
+#ifndef GL_AMD_query_buffer_object
+#define GL_AMD_query_buffer_object 1
+GLAPI int GLAD_GL_AMD_query_buffer_object;
+#endif
+#ifndef GL_ARB_ES2_compatibility
+#define GL_ARB_ES2_compatibility 1
+GLAPI int GLAD_GL_ARB_ES2_compatibility;
+typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC)();
+GLAPI PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler;
+#define glReleaseShaderCompiler glad_glReleaseShaderCompiler
+typedef void (APIENTRYP PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length);
+GLAPI PFNGLSHADERBINARYPROC glad_glShaderBinary;
+#define glShaderBinary glad_glShaderBinary
+typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+GLAPI PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat;
+#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat
+typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f);
+GLAPI PFNGLDEPTHRANGEFPROC glad_glDepthRangef;
+#define glDepthRangef glad_glDepthRangef
+typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC)(GLfloat d);
+GLAPI PFNGLCLEARDEPTHFPROC glad_glClearDepthf;
+#define glClearDepthf glad_glClearDepthf
+#endif
+#ifndef GL_ARB_ES3_compatibility
+#define GL_ARB_ES3_compatibility 1
+GLAPI int GLAD_GL_ARB_ES3_compatibility;
+#endif
+#ifndef GL_ARB_buffer_storage
+#define GL_ARB_buffer_storage 1
+GLAPI int GLAD_GL_ARB_buffer_storage;
+typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC)(GLenum target, GLsizeiptr size, const void* data, GLbitfield flags);
+GLAPI PFNGLBUFFERSTORAGEPROC glad_glBufferStorage;
+#define glBufferStorage glad_glBufferStorage
+#endif
+#ifndef GL_ARB_compatibility
+#define GL_ARB_compatibility 1
+GLAPI int GLAD_GL_ARB_compatibility;
+#endif
+#ifndef GL_ARB_compressed_texture_pixel_storage
+#define GL_ARB_compressed_texture_pixel_storage 1
+GLAPI int GLAD_GL_ARB_compressed_texture_pixel_storage;
+#endif
+#ifndef GL_ARB_debug_output
+#define GL_ARB_debug_output 1
+GLAPI int GLAD_GL_ARB_debug_output;
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled);
+GLAPI PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB;
+#define glDebugMessageControlARB glad_glDebugMessageControlARB
+typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf);
+GLAPI PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB;
+#define glDebugMessageInsertARB glad_glDebugMessageInsertARB
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC)(GLDEBUGPROCARB callback, const void* userParam);
+GLAPI PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB;
+#define glDebugMessageCallbackARB glad_glDebugMessageCallbackARB
+typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC)(GLuint count, GLsizei bufSize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog);
+GLAPI PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB;
+#define glGetDebugMessageLogARB glad_glGetDebugMessageLogARB
+#endif
+#ifndef GL_ARB_depth_buffer_float
+#define GL_ARB_depth_buffer_float 1
+GLAPI int GLAD_GL_ARB_depth_buffer_float;
+#endif
+#ifndef GL_ARB_depth_clamp
+#define GL_ARB_depth_clamp 1
+GLAPI int GLAD_GL_ARB_depth_clamp;
+#endif
+#ifndef GL_ARB_depth_texture
+#define GL_ARB_depth_texture 1
+GLAPI int GLAD_GL_ARB_depth_texture;
+#endif
+#ifndef GL_ARB_draw_buffers
+#define GL_ARB_draw_buffers 1
+GLAPI int GLAD_GL_ARB_draw_buffers;
+typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC)(GLsizei n, const GLenum* bufs);
+GLAPI PFNGLDRAWBUFFERSARBPROC glad_glDrawBuffersARB;
+#define glDrawBuffersARB glad_glDrawBuffersARB
+#endif
+#ifndef GL_ARB_draw_buffers_blend
+#define GL_ARB_draw_buffers_blend 1
+GLAPI int GLAD_GL_ARB_draw_buffers_blend;
+typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC)(GLuint buf, GLenum mode);
+GLAPI PFNGLBLENDEQUATIONIARBPROC glad_glBlendEquationiARB;
+#define glBlendEquationiARB glad_glBlendEquationiARB
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+GLAPI PFNGLBLENDEQUATIONSEPARATEIARBPROC glad_glBlendEquationSeparateiARB;
+#define glBlendEquationSeparateiARB glad_glBlendEquationSeparateiARB
+typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC)(GLuint buf, GLenum src, GLenum dst);
+GLAPI PFNGLBLENDFUNCIARBPROC glad_glBlendFunciARB;
+#define glBlendFunciARB glad_glBlendFunciARB
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GLAPI PFNGLBLENDFUNCSEPARATEIARBPROC glad_glBlendFuncSeparateiARB;
+#define glBlendFuncSeparateiARB glad_glBlendFuncSeparateiARB
+#endif
+#ifndef GL_ARB_explicit_attrib_location
+#define GL_ARB_explicit_attrib_location 1
+GLAPI int GLAD_GL_ARB_explicit_attrib_location;
+#endif
+#ifndef GL_ARB_explicit_uniform_location
+#define GL_ARB_explicit_uniform_location 1
+GLAPI int GLAD_GL_ARB_explicit_uniform_location;
+#endif
+#ifndef GL_ARB_fragment_program
+#define GL_ARB_fragment_program 1
+GLAPI int GLAD_GL_ARB_fragment_program;
+typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC)(GLenum target, GLenum format, GLsizei len, const void* string);
+GLAPI PFNGLPROGRAMSTRINGARBPROC glad_glProgramStringARB;
+#define glProgramStringARB glad_glProgramStringARB
+typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC)(GLenum target, GLuint program);
+GLAPI PFNGLBINDPROGRAMARBPROC glad_glBindProgramARB;
+#define glBindProgramARB glad_glBindProgramARB
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC)(GLsizei n, const GLuint* programs);
+GLAPI PFNGLDELETEPROGRAMSARBPROC glad_glDeleteProgramsARB;
+#define glDeleteProgramsARB glad_glDeleteProgramsARB
+typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC)(GLsizei n, GLuint* programs);
+GLAPI PFNGLGENPROGRAMSARBPROC glad_glGenProgramsARB;
+#define glGenProgramsARB glad_glGenProgramsARB
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC)(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI PFNGLPROGRAMENVPARAMETER4DARBPROC glad_glProgramEnvParameter4dARB;
+#define glProgramEnvParameter4dARB glad_glProgramEnvParameter4dARB
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC)(GLenum target, GLuint index, const GLdouble* params);
+GLAPI PFNGLPROGRAMENVPARAMETER4DVARBPROC glad_glProgramEnvParameter4dvARB;
+#define glProgramEnvParameter4dvARB glad_glProgramEnvParameter4dvARB
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC)(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI PFNGLPROGRAMENVPARAMETER4FARBPROC glad_glProgramEnvParameter4fARB;
+#define glProgramEnvParameter4fARB glad_glProgramEnvParameter4fARB
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC)(GLenum target, GLuint index, const GLfloat* params);
+GLAPI PFNGLPROGRAMENVPARAMETER4FVARBPROC glad_glProgramEnvParameter4fvARB;
+#define glProgramEnvParameter4fvARB glad_glProgramEnvParameter4fvARB
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC)(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI PFNGLPROGRAMLOCALPARAMETER4DARBPROC glad_glProgramLocalParameter4dARB;
+#define glProgramLocalParameter4dARB glad_glProgramLocalParameter4dARB
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)(GLenum target, GLuint index, const GLdouble* params);
+GLAPI PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glad_glProgramLocalParameter4dvARB;
+#define glProgramLocalParameter4dvARB glad_glProgramLocalParameter4dvARB
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC)(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI PFNGLPROGRAMLOCALPARAMETER4FARBPROC glad_glProgramLocalParameter4fARB;
+#define glProgramLocalParameter4fARB glad_glProgramLocalParameter4fARB
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)(GLenum target, GLuint index, const GLfloat* params);
+GLAPI PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glad_glProgramLocalParameter4fvARB;
+#define glProgramLocalParameter4fvARB glad_glProgramLocalParameter4fvARB
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC)(GLenum target, GLuint index, GLdouble* params);
+GLAPI PFNGLGETPROGRAMENVPARAMETERDVARBPROC glad_glGetProgramEnvParameterdvARB;
+#define glGetProgramEnvParameterdvARB glad_glGetProgramEnvParameterdvARB
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC)(GLenum target, GLuint index, GLfloat* params);
+GLAPI PFNGLGETPROGRAMENVPARAMETERFVARBPROC glad_glGetProgramEnvParameterfvARB;
+#define glGetProgramEnvParameterfvARB glad_glGetProgramEnvParameterfvARB
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)(GLenum target, GLuint index, GLdouble* params);
+GLAPI PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glad_glGetProgramLocalParameterdvARB;
+#define glGetProgramLocalParameterdvARB glad_glGetProgramLocalParameterdvARB
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)(GLenum target, GLuint index, GLfloat* params);
+GLAPI PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glad_glGetProgramLocalParameterfvARB;
+#define glGetProgramLocalParameterfvARB glad_glGetProgramLocalParameterfvARB
+typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC)(GLenum target, GLenum pname, GLint* params);
+GLAPI PFNGLGETPROGRAMIVARBPROC glad_glGetProgramivARB;
+#define glGetProgramivARB glad_glGetProgramivARB
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC)(GLenum target, GLenum pname, void* string);
+GLAPI PFNGLGETPROGRAMSTRINGARBPROC glad_glGetProgramStringARB;
+#define glGetProgramStringARB glad_glGetProgramStringARB
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC)(GLuint program);
+GLAPI PFNGLISPROGRAMARBPROC glad_glIsProgramARB;
+#define glIsProgramARB glad_glIsProgramARB
+#endif
+#ifndef GL_ARB_fragment_shader
+#define GL_ARB_fragment_shader 1
+GLAPI int GLAD_GL_ARB_fragment_shader;
+#endif
+#ifndef GL_ARB_framebuffer_object
+#define GL_ARB_framebuffer_object 1
+GLAPI int GLAD_GL_ARB_framebuffer_object;
+#endif
+#ifndef GL_ARB_framebuffer_sRGB
+#define GL_ARB_framebuffer_sRGB 1
+GLAPI int GLAD_GL_ARB_framebuffer_sRGB;
+#endif
+#ifndef GL_ARB_multisample
+#define GL_ARB_multisample 1
+GLAPI int GLAD_GL_ARB_multisample;
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC)(GLfloat value, GLboolean invert);
+GLAPI PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB;
+#define glSampleCoverageARB glad_glSampleCoverageARB
+#endif
+#ifndef GL_ARB_sample_locations
+#define GL_ARB_sample_locations 1
+GLAPI int GLAD_GL_ARB_sample_locations;
+typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)(GLenum target, GLuint start, GLsizei count, const GLfloat* v);
+GLAPI PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glFramebufferSampleLocationsfvARB;
+#define glFramebufferSampleLocationsfvARB glad_glFramebufferSampleLocationsfvARB
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)(GLuint framebuffer, GLuint start, GLsizei count, const GLfloat* v);
+GLAPI PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glNamedFramebufferSampleLocationsfvARB;
+#define glNamedFramebufferSampleLocationsfvARB glad_glNamedFramebufferSampleLocationsfvARB
+typedef void (APIENTRYP PFNGLEVALUATEDEPTHVALUESARBPROC)();
+GLAPI PFNGLEVALUATEDEPTHVALUESARBPROC glad_glEvaluateDepthValuesARB;
+#define glEvaluateDepthValuesARB glad_glEvaluateDepthValuesARB
+#endif
+#ifndef GL_ARB_texture_compression
+#define GL_ARB_texture_compression 1
+GLAPI int GLAD_GL_ARB_texture_compression;
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data);
+GLAPI PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glad_glCompressedTexImage3DARB;
+#define glCompressedTexImage3DARB glad_glCompressedTexImage3DARB
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data);
+GLAPI PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glad_glCompressedTexImage2DARB;
+#define glCompressedTexImage2DARB glad_glCompressedTexImage2DARB
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void* data);
+GLAPI PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glad_glCompressedTexImage1DARB;
+#define glCompressedTexImage1DARB glad_glCompressedTexImage1DARB
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data);
+GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glad_glCompressedTexSubImage3DARB;
+#define glCompressedTexSubImage3DARB glad_glCompressedTexSubImage3DARB
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data);
+GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glad_glCompressedTexSubImage2DARB;
+#define glCompressedTexSubImage2DARB glad_glCompressedTexSubImage2DARB
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data);
+GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glad_glCompressedTexSubImage1DARB;
+#define glCompressedTexSubImage1DARB glad_glCompressedTexSubImage1DARB
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)(GLenum target, GLint level, void* img);
+GLAPI PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glad_glGetCompressedTexImageARB;
+#define glGetCompressedTexImageARB glad_glGetCompressedTexImageARB
+#endif
+#ifndef GL_ARB_texture_float
+#define GL_ARB_texture_float 1
+GLAPI int GLAD_GL_ARB_texture_float;
+#endif
+#ifndef GL_ARB_texture_multisample
+#define GL_ARB_texture_multisample 1
+GLAPI int GLAD_GL_ARB_texture_multisample;
+#endif
+#ifndef GL_ARB_texture_non_power_of_two
+#define GL_ARB_texture_non_power_of_two 1
+GLAPI int GLAD_GL_ARB_texture_non_power_of_two;
+#endif
+#ifndef GL_ARB_texture_rg
+#define GL_ARB_texture_rg 1
+GLAPI int GLAD_GL_ARB_texture_rg;
+#endif
+#ifndef GL_ARB_texture_swizzle
+#define GL_ARB_texture_swizzle 1
+GLAPI int GLAD_GL_ARB_texture_swizzle;
+#endif
+#ifndef GL_ARB_uniform_buffer_object
+#define GL_ARB_uniform_buffer_object 1
+GLAPI int GLAD_GL_ARB_uniform_buffer_object;
+#endif
+#ifndef GL_ARB_vertex_array_object
+#define GL_ARB_vertex_array_object 1
+GLAPI int GLAD_GL_ARB_vertex_array_object;
+#endif
+#ifndef GL_ARB_vertex_attrib_binding
+#define GL_ARB_vertex_attrib_binding 1
+GLAPI int GLAD_GL_ARB_vertex_attrib_binding;
+typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC)(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+GLAPI PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer;
+#define glBindVertexBuffer glad_glBindVertexBuffer
+typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+GLAPI PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat;
+#define glVertexAttribFormat glad_glVertexAttribFormat
+typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+GLAPI PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat;
+#define glVertexAttribIFormat glad_glVertexAttribIFormat
+typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+GLAPI PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat;
+#define glVertexAttribLFormat glad_glVertexAttribLFormat
+typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC)(GLuint attribindex, GLuint bindingindex);
+GLAPI PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding;
+#define glVertexAttribBinding glad_glVertexAttribBinding
+typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC)(GLuint bindingindex, GLuint divisor);
+GLAPI PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor;
+#define glVertexBindingDivisor glad_glVertexBindingDivisor
+#endif
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_ARB_vertex_buffer_object 1
+GLAPI int GLAD_GL_ARB_vertex_buffer_object;
+typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC)(GLenum target, GLuint buffer);
+GLAPI PFNGLBINDBUFFERARBPROC glad_glBindBufferARB;
+#define glBindBufferARB glad_glBindBufferARB
+typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC)(GLsizei n, const GLuint* buffers);
+GLAPI PFNGLDELETEBUFFERSARBPROC glad_glDeleteBuffersARB;
+#define glDeleteBuffersARB glad_glDeleteBuffersARB
+typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC)(GLsizei n, GLuint* buffers);
+GLAPI PFNGLGENBUFFERSARBPROC glad_glGenBuffersARB;
+#define glGenBuffersARB glad_glGenBuffersARB
+typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC)(GLuint buffer);
+GLAPI PFNGLISBUFFERARBPROC glad_glIsBufferARB;
+#define glIsBufferARB glad_glIsBufferARB
+typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC)(GLenum target, GLsizeiptrARB size, const void* data, GLenum usage);
+GLAPI PFNGLBUFFERDATAARBPROC glad_glBufferDataARB;
+#define glBufferDataARB glad_glBufferDataARB
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC)(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void* data);
+GLAPI PFNGLBUFFERSUBDATAARBPROC glad_glBufferSubDataARB;
+#define glBufferSubDataARB glad_glBufferSubDataARB
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC)(GLenum target, GLintptrARB offset, GLsizeiptrARB size, void* data);
+GLAPI PFNGLGETBUFFERSUBDATAARBPROC glad_glGetBufferSubDataARB;
+#define glGetBufferSubDataARB glad_glGetBufferSubDataARB
+typedef void* (APIENTRYP PFNGLMAPBUFFERARBPROC)(GLenum target, GLenum access);
+GLAPI PFNGLMAPBUFFERARBPROC glad_glMapBufferARB;
+#define glMapBufferARB glad_glMapBufferARB
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC)(GLenum target);
+GLAPI PFNGLUNMAPBUFFERARBPROC glad_glUnmapBufferARB;
+#define glUnmapBufferARB glad_glUnmapBufferARB
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC)(GLenum target, GLenum pname, GLint* params);
+GLAPI PFNGLGETBUFFERPARAMETERIVARBPROC glad_glGetBufferParameterivARB;
+#define glGetBufferParameterivARB glad_glGetBufferParameterivARB
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC)(GLenum target, GLenum pname, void** params);
+GLAPI PFNGLGETBUFFERPOINTERVARBPROC glad_glGetBufferPointervARB;
+#define glGetBufferPointervARB glad_glGetBufferPointervARB
+#endif
+#ifndef GL_ARB_vertex_program
+#define GL_ARB_vertex_program 1
+GLAPI int GLAD_GL_ARB_vertex_program;
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC)(GLuint index, GLdouble x);
+GLAPI PFNGLVERTEXATTRIB1DARBPROC glad_glVertexAttrib1dARB;
+#define glVertexAttrib1dARB glad_glVertexAttrib1dARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC)(GLuint index, const GLdouble* v);
+GLAPI PFNGLVERTEXATTRIB1DVARBPROC glad_glVertexAttrib1dvARB;
+#define glVertexAttrib1dvARB glad_glVertexAttrib1dvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC)(GLuint index, GLfloat x);
+GLAPI PFNGLVERTEXATTRIB1FARBPROC glad_glVertexAttrib1fARB;
+#define glVertexAttrib1fARB glad_glVertexAttrib1fARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC)(GLuint index, const GLfloat* v);
+GLAPI PFNGLVERTEXATTRIB1FVARBPROC glad_glVertexAttrib1fvARB;
+#define glVertexAttrib1fvARB glad_glVertexAttrib1fvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC)(GLuint index, GLshort x);
+GLAPI PFNGLVERTEXATTRIB1SARBPROC glad_glVertexAttrib1sARB;
+#define glVertexAttrib1sARB glad_glVertexAttrib1sARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC)(GLuint index, const GLshort* v);
+GLAPI PFNGLVERTEXATTRIB1SVARBPROC glad_glVertexAttrib1svARB;
+#define glVertexAttrib1svARB glad_glVertexAttrib1svARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC)(GLuint index, GLdouble x, GLdouble y);
+GLAPI PFNGLVERTEXATTRIB2DARBPROC glad_glVertexAttrib2dARB;
+#define glVertexAttrib2dARB glad_glVertexAttrib2dARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC)(GLuint index, const GLdouble* v);
+GLAPI PFNGLVERTEXATTRIB2DVARBPROC glad_glVertexAttrib2dvARB;
+#define glVertexAttrib2dvARB glad_glVertexAttrib2dvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC)(GLuint index, GLfloat x, GLfloat y);
+GLAPI PFNGLVERTEXATTRIB2FARBPROC glad_glVertexAttrib2fARB;
+#define glVertexAttrib2fARB glad_glVertexAttrib2fARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC)(GLuint index, const GLfloat* v);
+GLAPI PFNGLVERTEXATTRIB2FVARBPROC glad_glVertexAttrib2fvARB;
+#define glVertexAttrib2fvARB glad_glVertexAttrib2fvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC)(GLuint index, GLshort x, GLshort y);
+GLAPI PFNGLVERTEXATTRIB2SARBPROC glad_glVertexAttrib2sARB;
+#define glVertexAttrib2sARB glad_glVertexAttrib2sARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC)(GLuint index, const GLshort* v);
+GLAPI PFNGLVERTEXATTRIB2SVARBPROC glad_glVertexAttrib2svARB;
+#define glVertexAttrib2svARB glad_glVertexAttrib2svARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI PFNGLVERTEXATTRIB3DARBPROC glad_glVertexAttrib3dARB;
+#define glVertexAttrib3dARB glad_glVertexAttrib3dARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC)(GLuint index, const GLdouble* v);
+GLAPI PFNGLVERTEXATTRIB3DVARBPROC glad_glVertexAttrib3dvARB;
+#define glVertexAttrib3dvARB glad_glVertexAttrib3dvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z);
+GLAPI PFNGLVERTEXATTRIB3FARBPROC glad_glVertexAttrib3fARB;
+#define glVertexAttrib3fARB glad_glVertexAttrib3fARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC)(GLuint index, const GLfloat* v);
+GLAPI PFNGLVERTEXATTRIB3FVARBPROC glad_glVertexAttrib3fvARB;
+#define glVertexAttrib3fvARB glad_glVertexAttrib3fvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC)(GLuint index, GLshort x, GLshort y, GLshort z);
+GLAPI PFNGLVERTEXATTRIB3SARBPROC glad_glVertexAttrib3sARB;
+#define glVertexAttrib3sARB glad_glVertexAttrib3sARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC)(GLuint index, const GLshort* v);
+GLAPI PFNGLVERTEXATTRIB3SVARBPROC glad_glVertexAttrib3svARB;
+#define glVertexAttrib3svARB glad_glVertexAttrib3svARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC)(GLuint index, const GLbyte* v);
+GLAPI PFNGLVERTEXATTRIB4NBVARBPROC glad_glVertexAttrib4NbvARB;
+#define glVertexAttrib4NbvARB glad_glVertexAttrib4NbvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC)(GLuint index, const GLint* v);
+GLAPI PFNGLVERTEXATTRIB4NIVARBPROC glad_glVertexAttrib4NivARB;
+#define glVertexAttrib4NivARB glad_glVertexAttrib4NivARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC)(GLuint index, const GLshort* v);
+GLAPI PFNGLVERTEXATTRIB4NSVARBPROC glad_glVertexAttrib4NsvARB;
+#define glVertexAttrib4NsvARB glad_glVertexAttrib4NsvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+GLAPI PFNGLVERTEXATTRIB4NUBARBPROC glad_glVertexAttrib4NubARB;
+#define glVertexAttrib4NubARB glad_glVertexAttrib4NubARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC)(GLuint index, const GLubyte* v);
+GLAPI PFNGLVERTEXATTRIB4NUBVARBPROC glad_glVertexAttrib4NubvARB;
+#define glVertexAttrib4NubvARB glad_glVertexAttrib4NubvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC)(GLuint index, const GLuint* v);
+GLAPI PFNGLVERTEXATTRIB4NUIVARBPROC glad_glVertexAttrib4NuivARB;
+#define glVertexAttrib4NuivARB glad_glVertexAttrib4NuivARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC)(GLuint index, const GLushort* v);
+GLAPI PFNGLVERTEXATTRIB4NUSVARBPROC glad_glVertexAttrib4NusvARB;
+#define glVertexAttrib4NusvARB glad_glVertexAttrib4NusvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC)(GLuint index, const GLbyte* v);
+GLAPI PFNGLVERTEXATTRIB4BVARBPROC glad_glVertexAttrib4bvARB;
+#define glVertexAttrib4bvARB glad_glVertexAttrib4bvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI PFNGLVERTEXATTRIB4DARBPROC glad_glVertexAttrib4dARB;
+#define glVertexAttrib4dARB glad_glVertexAttrib4dARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC)(GLuint index, const GLdouble* v);
+GLAPI PFNGLVERTEXATTRIB4DVARBPROC glad_glVertexAttrib4dvARB;
+#define glVertexAttrib4dvARB glad_glVertexAttrib4dvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI PFNGLVERTEXATTRIB4FARBPROC glad_glVertexAttrib4fARB;
+#define glVertexAttrib4fARB glad_glVertexAttrib4fARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC)(GLuint index, const GLfloat* v);
+GLAPI PFNGLVERTEXATTRIB4FVARBPROC glad_glVertexAttrib4fvARB;
+#define glVertexAttrib4fvARB glad_glVertexAttrib4fvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC)(GLuint index, const GLint* v);
+GLAPI PFNGLVERTEXATTRIB4IVARBPROC glad_glVertexAttrib4ivARB;
+#define glVertexAttrib4ivARB glad_glVertexAttrib4ivARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI PFNGLVERTEXATTRIB4SARBPROC glad_glVertexAttrib4sARB;
+#define glVertexAttrib4sARB glad_glVertexAttrib4sARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC)(GLuint index, const GLshort* v);
+GLAPI PFNGLVERTEXATTRIB4SVARBPROC glad_glVertexAttrib4svARB;
+#define glVertexAttrib4svARB glad_glVertexAttrib4svARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC)(GLuint index, const GLubyte* v);
+GLAPI PFNGLVERTEXATTRIB4UBVARBPROC glad_glVertexAttrib4ubvARB;
+#define glVertexAttrib4ubvARB glad_glVertexAttrib4ubvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC)(GLuint index, const GLuint* v);
+GLAPI PFNGLVERTEXATTRIB4UIVARBPROC glad_glVertexAttrib4uivARB;
+#define glVertexAttrib4uivARB glad_glVertexAttrib4uivARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC)(GLuint index, const GLushort* v);
+GLAPI PFNGLVERTEXATTRIB4USVARBPROC glad_glVertexAttrib4usvARB;
+#define glVertexAttrib4usvARB glad_glVertexAttrib4usvARB
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
+GLAPI PFNGLVERTEXATTRIBPOINTERARBPROC glad_glVertexAttribPointerARB;
+#define glVertexAttribPointerARB glad_glVertexAttribPointerARB
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC)(GLuint index);
+GLAPI PFNGLENABLEVERTEXATTRIBARRAYARBPROC glad_glEnableVertexAttribArrayARB;
+#define glEnableVertexAttribArrayARB glad_glEnableVertexAttribArrayARB
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)(GLuint index);
+GLAPI PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glad_glDisableVertexAttribArrayARB;
+#define glDisableVertexAttribArrayARB glad_glDisableVertexAttribArrayARB
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC)(GLuint index, GLenum pname, GLdouble* params);
+GLAPI PFNGLGETVERTEXATTRIBDVARBPROC glad_glGetVertexAttribdvARB;
+#define glGetVertexAttribdvARB glad_glGetVertexAttribdvARB
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC)(GLuint index, GLenum pname, GLfloat* params);
+GLAPI PFNGLGETVERTEXATTRIBFVARBPROC glad_glGetVertexAttribfvARB;
+#define glGetVertexAttribfvARB glad_glGetVertexAttribfvARB
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC)(GLuint index, GLenum pname, GLint* params);
+GLAPI PFNGLGETVERTEXATTRIBIVARBPROC glad_glGetVertexAttribivARB;
+#define glGetVertexAttribivARB glad_glGetVertexAttribivARB
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC)(GLuint index, GLenum pname, void** pointer);
+GLAPI PFNGLGETVERTEXATTRIBPOINTERVARBPROC glad_glGetVertexAttribPointervARB;
+#define glGetVertexAttribPointervARB glad_glGetVertexAttribPointervARB
+#endif
+#ifndef GL_ARB_vertex_shader
+#define GL_ARB_vertex_shader 1
+GLAPI int GLAD_GL_ARB_vertex_shader;
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC)(GLhandleARB programObj, GLuint index, const GLcharARB* name);
+GLAPI PFNGLBINDATTRIBLOCATIONARBPROC glad_glBindAttribLocationARB;
+#define glBindAttribLocationARB glad_glBindAttribLocationARB
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC)(GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei* length, GLint* size, GLenum* type, GLcharARB* name);
+GLAPI PFNGLGETACTIVEATTRIBARBPROC glad_glGetActiveAttribARB;
+#define glGetActiveAttribARB glad_glGetActiveAttribARB
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC)(GLhandleARB programObj, const GLcharARB* name);
+GLAPI PFNGLGETATTRIBLOCATIONARBPROC glad_glGetAttribLocationARB;
+#define glGetAttribLocationARB glad_glGetAttribLocationARB
+#endif
+#ifndef GL_ATI_element_array
+#define GL_ATI_element_array 1
+GLAPI int GLAD_GL_ATI_element_array;
+typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC)(GLenum type, const void* pointer);
+GLAPI PFNGLELEMENTPOINTERATIPROC glad_glElementPointerATI;
+#define glElementPointerATI glad_glElementPointerATI
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC)(GLenum mode, GLsizei count);
+GLAPI PFNGLDRAWELEMENTARRAYATIPROC glad_glDrawElementArrayATI;
+#define glDrawElementArrayATI glad_glDrawElementArrayATI
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count);
+GLAPI PFNGLDRAWRANGEELEMENTARRAYATIPROC glad_glDrawRangeElementArrayATI;
+#define glDrawRangeElementArrayATI glad_glDrawRangeElementArrayATI
+#endif
+#ifndef GL_ATI_fragment_shader
+#define GL_ATI_fragment_shader 1
+GLAPI int GLAD_GL_ATI_fragment_shader;
+typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC)(GLuint range);
+GLAPI PFNGLGENFRAGMENTSHADERSATIPROC glad_glGenFragmentShadersATI;
+#define glGenFragmentShadersATI glad_glGenFragmentShadersATI
+typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC)(GLuint id);
+GLAPI PFNGLBINDFRAGMENTSHADERATIPROC glad_glBindFragmentShaderATI;
+#define glBindFragmentShaderATI glad_glBindFragmentShaderATI
+typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC)(GLuint id);
+GLAPI PFNGLDELETEFRAGMENTSHADERATIPROC glad_glDeleteFragmentShaderATI;
+#define glDeleteFragmentShaderATI glad_glDeleteFragmentShaderATI
+typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC)();
+GLAPI PFNGLBEGINFRAGMENTSHADERATIPROC glad_glBeginFragmentShaderATI;
+#define glBeginFragmentShaderATI glad_glBeginFragmentShaderATI
+typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC)();
+GLAPI PFNGLENDFRAGMENTSHADERATIPROC glad_glEndFragmentShaderATI;
+#define glEndFragmentShaderATI glad_glEndFragmentShaderATI
+typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC)(GLuint dst, GLuint coord, GLenum swizzle);
+GLAPI PFNGLPASSTEXCOORDATIPROC glad_glPassTexCoordATI;
+#define glPassTexCoordATI glad_glPassTexCoordATI
+typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC)(GLuint dst, GLuint interp, GLenum swizzle);
+GLAPI PFNGLSAMPLEMAPATIPROC glad_glSampleMapATI;
+#define glSampleMapATI glad_glSampleMapATI
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC)(GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+GLAPI PFNGLCOLORFRAGMENTOP1ATIPROC glad_glColorFragmentOp1ATI;
+#define glColorFragmentOp1ATI glad_glColorFragmentOp1ATI
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC)(GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+GLAPI PFNGLCOLORFRAGMENTOP2ATIPROC glad_glColorFragmentOp2ATI;
+#define glColorFragmentOp2ATI glad_glColorFragmentOp2ATI
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC)(GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+GLAPI PFNGLCOLORFRAGMENTOP3ATIPROC glad_glColorFragmentOp3ATI;
+#define glColorFragmentOp3ATI glad_glColorFragmentOp3ATI
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC)(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+GLAPI PFNGLALPHAFRAGMENTOP1ATIPROC glad_glAlphaFragmentOp1ATI;
+#define glAlphaFragmentOp1ATI glad_glAlphaFragmentOp1ATI
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC)(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+GLAPI PFNGLALPHAFRAGMENTOP2ATIPROC glad_glAlphaFragmentOp2ATI;
+#define glAlphaFragmentOp2ATI glad_glAlphaFragmentOp2ATI
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC)(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+GLAPI PFNGLALPHAFRAGMENTOP3ATIPROC glad_glAlphaFragmentOp3ATI;
+#define glAlphaFragmentOp3ATI glad_glAlphaFragmentOp3ATI
+typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC)(GLuint dst, const GLfloat* value);
+GLAPI PFNGLSETFRAGMENTSHADERCONSTANTATIPROC glad_glSetFragmentShaderConstantATI;
+#define glSetFragmentShaderConstantATI glad_glSetFragmentShaderConstantATI
+#endif
+#ifndef GL_ATI_vertex_array_object
+#define GL_ATI_vertex_array_object 1
+GLAPI int GLAD_GL_ATI_vertex_array_object;
+typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC)(GLsizei size, const void* pointer, GLenum usage);
+GLAPI PFNGLNEWOBJECTBUFFERATIPROC glad_glNewObjectBufferATI;
+#define glNewObjectBufferATI glad_glNewObjectBufferATI
+typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC)(GLuint buffer);
+GLAPI PFNGLISOBJECTBUFFERATIPROC glad_glIsObjectBufferATI;
+#define glIsObjectBufferATI glad_glIsObjectBufferATI
+typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC)(GLuint buffer, GLuint offset, GLsizei size, const void* pointer, GLenum preserve);
+GLAPI PFNGLUPDATEOBJECTBUFFERATIPROC glad_glUpdateObjectBufferATI;
+#define glUpdateObjectBufferATI glad_glUpdateObjectBufferATI
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC)(GLuint buffer, GLenum pname, GLfloat* params);
+GLAPI PFNGLGETOBJECTBUFFERFVATIPROC glad_glGetObjectBufferfvATI;
+#define glGetObjectBufferfvATI glad_glGetObjectBufferfvATI
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC)(GLuint buffer, GLenum pname, GLint* params);
+GLAPI PFNGLGETOBJECTBUFFERIVATIPROC glad_glGetObjectBufferivATI;
+#define glGetObjectBufferivATI glad_glGetObjectBufferivATI
+typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC)(GLuint buffer);
+GLAPI PFNGLFREEOBJECTBUFFERATIPROC glad_glFreeObjectBufferATI;
+#define glFreeObjectBufferATI glad_glFreeObjectBufferATI
+typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC)(GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+GLAPI PFNGLARRAYOBJECTATIPROC glad_glArrayObjectATI;
+#define glArrayObjectATI glad_glArrayObjectATI
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC)(GLenum array, GLenum pname, GLfloat* params);
+GLAPI PFNGLGETARRAYOBJECTFVATIPROC glad_glGetArrayObjectfvATI;
+#define glGetArrayObjectfvATI glad_glGetArrayObjectfvATI
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC)(GLenum array, GLenum pname, GLint* params);
+GLAPI PFNGLGETARRAYOBJECTIVATIPROC glad_glGetArrayObjectivATI;
+#define glGetArrayObjectivATI glad_glGetArrayObjectivATI
+typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC)(GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+GLAPI PFNGLVARIANTARRAYOBJECTATIPROC glad_glVariantArrayObjectATI;
+#define glVariantArrayObjectATI glad_glVariantArrayObjectATI
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC)(GLuint id, GLenum pname, GLfloat* params);
+GLAPI PFNGLGETVARIANTARRAYOBJECTFVATIPROC glad_glGetVariantArrayObjectfvATI;
+#define glGetVariantArrayObjectfvATI glad_glGetVariantArrayObjectfvATI
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC)(GLuint id, GLenum pname, GLint* params);
+GLAPI PFNGLGETVARIANTARRAYOBJECTIVATIPROC glad_glGetVariantArrayObjectivATI;
+#define glGetVariantArrayObjectivATI glad_glGetVariantArrayObjectivATI
+#endif
+#ifndef GL_EXT_blend_color
+#define GL_EXT_blend_color 1
+GLAPI int GLAD_GL_EXT_blend_color;
+typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GLAPI PFNGLBLENDCOLOREXTPROC glad_glBlendColorEXT;
+#define glBlendColorEXT glad_glBlendColorEXT
+#endif
+#ifndef GL_EXT_blend_equation_separate
+#define GL_EXT_blend_equation_separate 1
+GLAPI int GLAD_GL_EXT_blend_equation_separate;
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC)(GLenum modeRGB, GLenum modeAlpha);
+GLAPI PFNGLBLENDEQUATIONSEPARATEEXTPROC glad_glBlendEquationSeparateEXT;
+#define glBlendEquationSeparateEXT glad_glBlendEquationSeparateEXT
+#endif
+#ifndef GL_EXT_blend_func_separate
+#define GL_EXT_blend_func_separate 1
+GLAPI int GLAD_GL_EXT_blend_func_separate;
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+GLAPI PFNGLBLENDFUNCSEPARATEEXTPROC glad_glBlendFuncSeparateEXT;
+#define glBlendFuncSeparateEXT glad_glBlendFuncSeparateEXT
+#endif
+#ifndef GL_EXT_framebuffer_blit
+#define GL_EXT_framebuffer_blit 1
+GLAPI int GLAD_GL_EXT_framebuffer_blit;
+typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+GLAPI PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT;
+#define glBlitFramebufferEXT glad_glBlitFramebufferEXT
+#endif
+#ifndef GL_EXT_framebuffer_multisample
+#define GL_EXT_framebuffer_multisample 1
+GLAPI int GLAD_GL_EXT_framebuffer_multisample;
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT;
+#define glRenderbufferStorageMultisampleEXT glad_glRenderbufferStorageMultisampleEXT
+#endif
+#ifndef GL_EXT_framebuffer_multisample_blit_scaled
+#define GL_EXT_framebuffer_multisample_blit_scaled 1
+GLAPI int GLAD_GL_EXT_framebuffer_multisample_blit_scaled;
+#endif
+#ifndef GL_EXT_framebuffer_object
+#define GL_EXT_framebuffer_object 1
+GLAPI int GLAD_GL_EXT_framebuffer_object;
+typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC)(GLuint renderbuffer);
+GLAPI PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT;
+#define glIsRenderbufferEXT glad_glIsRenderbufferEXT
+typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC)(GLenum target, GLuint renderbuffer);
+GLAPI PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT;
+#define glBindRenderbufferEXT glad_glBindRenderbufferEXT
+typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC)(GLsizei n, const GLuint* renderbuffers);
+GLAPI PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT;
+#define glDeleteRenderbuffersEXT glad_glDeleteRenderbuffersEXT
+typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC)(GLsizei n, GLuint* renderbuffers);
+GLAPI PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT;
+#define glGenRenderbuffersEXT glad_glGenRenderbuffersEXT
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT;
+#define glRenderbufferStorageEXT glad_glRenderbufferStorageEXT
+typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)(GLenum target, GLenum pname, GLint* params);
+GLAPI PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT;
+#define glGetRenderbufferParameterivEXT glad_glGetRenderbufferParameterivEXT
+typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC)(GLuint framebuffer);
+GLAPI PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT;
+#define glIsFramebufferEXT glad_glIsFramebufferEXT
+typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC)(GLenum target, GLuint framebuffer);
+GLAPI PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT;
+#define glBindFramebufferEXT glad_glBindFramebufferEXT
+typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC)(GLsizei n, const GLuint* framebuffers);
+GLAPI PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT;
+#define glDeleteFramebuffersEXT glad_glDeleteFramebuffersEXT
+typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC)(GLsizei n, GLuint* framebuffers);
+GLAPI PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT;
+#define glGenFramebuffersEXT glad_glGenFramebuffersEXT
+typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)(GLenum target);
+GLAPI PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT;
+#define glCheckFramebufferStatusEXT glad_glCheckFramebufferStatusEXT
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT;
+#define glFramebufferTexture1DEXT glad_glFramebufferTexture1DEXT
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT;
+#define glFramebufferTexture2DEXT glad_glFramebufferTexture2DEXT
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+GLAPI PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT;
+#define glFramebufferTexture3DEXT glad_glFramebufferTexture3DEXT
+typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GLAPI PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT;
+#define glFramebufferRenderbufferEXT glad_glFramebufferRenderbufferEXT
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)(GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT;
+#define glGetFramebufferAttachmentParameterivEXT glad_glGetFramebufferAttachmentParameterivEXT
+typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC)(GLenum target);
+GLAPI PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT;
+#define glGenerateMipmapEXT glad_glGenerateMipmapEXT
+#endif
+#ifndef GL_EXT_framebuffer_sRGB
+#define GL_EXT_framebuffer_sRGB 1
+GLAPI int GLAD_GL_EXT_framebuffer_sRGB;
+#endif
+#ifndef GL_EXT_index_array_formats
+#define GL_EXT_index_array_formats 1
+GLAPI int GLAD_GL_EXT_index_array_formats;
+#endif
+#ifndef GL_EXT_texture
+#define GL_EXT_texture 1
+GLAPI int GLAD_GL_EXT_texture;
+#endif
+#ifndef GL_EXT_texture_compression_s3tc
+#define GL_EXT_texture_compression_s3tc 1
+GLAPI int GLAD_GL_EXT_texture_compression_s3tc;
+#endif
+#ifndef GL_EXT_texture_sRGB
+#define GL_EXT_texture_sRGB 1
+GLAPI int GLAD_GL_EXT_texture_sRGB;
+#endif
+#ifndef GL_EXT_texture_swizzle
+#define GL_EXT_texture_swizzle 1
+GLAPI int GLAD_GL_EXT_texture_swizzle;
+#endif
+#ifndef GL_EXT_vertex_array
+#define GL_EXT_vertex_array 1
+GLAPI int GLAD_GL_EXT_vertex_array;
+typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC)(GLint i);
+GLAPI PFNGLARRAYELEMENTEXTPROC glad_glArrayElementEXT;
+#define glArrayElementEXT glad_glArrayElementEXT
+typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC)(GLint size, GLenum type, GLsizei stride, GLsizei count, const void* pointer);
+GLAPI PFNGLCOLORPOINTEREXTPROC glad_glColorPointerEXT;
+#define glColorPointerEXT glad_glColorPointerEXT
+typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC)(GLenum mode, GLint first, GLsizei count);
+GLAPI PFNGLDRAWARRAYSEXTPROC glad_glDrawArraysEXT;
+#define glDrawArraysEXT glad_glDrawArraysEXT
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC)(GLsizei stride, GLsizei count, const GLboolean* pointer);
+GLAPI PFNGLEDGEFLAGPOINTEREXTPROC glad_glEdgeFlagPointerEXT;
+#define glEdgeFlagPointerEXT glad_glEdgeFlagPointerEXT
+typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC)(GLenum pname, void** params);
+GLAPI PFNGLGETPOINTERVEXTPROC glad_glGetPointervEXT;
+#define glGetPointervEXT glad_glGetPointervEXT
+typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC)(GLenum type, GLsizei stride, GLsizei count, const void* pointer);
+GLAPI PFNGLINDEXPOINTEREXTPROC glad_glIndexPointerEXT;
+#define glIndexPointerEXT glad_glIndexPointerEXT
+typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC)(GLenum type, GLsizei stride, GLsizei count, const void* pointer);
+GLAPI PFNGLNORMALPOINTEREXTPROC glad_glNormalPointerEXT;
+#define glNormalPointerEXT glad_glNormalPointerEXT
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC)(GLint size, GLenum type, GLsizei stride, GLsizei count, const void* pointer);
+GLAPI PFNGLTEXCOORDPOINTEREXTPROC glad_glTexCoordPointerEXT;
+#define glTexCoordPointerEXT glad_glTexCoordPointerEXT
+typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC)(GLint size, GLenum type, GLsizei stride, GLsizei count, const void* pointer);
+GLAPI PFNGLVERTEXPOINTEREXTPROC glad_glVertexPointerEXT;
+#define glVertexPointerEXT glad_glVertexPointerEXT
+#endif
+#ifndef GL_EXT_vertex_shader
+#define GL_EXT_vertex_shader 1
+GLAPI int GLAD_GL_EXT_vertex_shader;
+typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC)();
+GLAPI PFNGLBEGINVERTEXSHADEREXTPROC glad_glBeginVertexShaderEXT;
+#define glBeginVertexShaderEXT glad_glBeginVertexShaderEXT
+typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC)();
+GLAPI PFNGLENDVERTEXSHADEREXTPROC glad_glEndVertexShaderEXT;
+#define glEndVertexShaderEXT glad_glEndVertexShaderEXT
+typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC)(GLuint id);
+GLAPI PFNGLBINDVERTEXSHADEREXTPROC glad_glBindVertexShaderEXT;
+#define glBindVertexShaderEXT glad_glBindVertexShaderEXT
+typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC)(GLuint range);
+GLAPI PFNGLGENVERTEXSHADERSEXTPROC glad_glGenVertexShadersEXT;
+#define glGenVertexShadersEXT glad_glGenVertexShadersEXT
+typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC)(GLuint id);
+GLAPI PFNGLDELETEVERTEXSHADEREXTPROC glad_glDeleteVertexShaderEXT;
+#define glDeleteVertexShaderEXT glad_glDeleteVertexShaderEXT
+typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC)(GLenum op, GLuint res, GLuint arg1);
+GLAPI PFNGLSHADEROP1EXTPROC glad_glShaderOp1EXT;
+#define glShaderOp1EXT glad_glShaderOp1EXT
+typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC)(GLenum op, GLuint res, GLuint arg1, GLuint arg2);
+GLAPI PFNGLSHADEROP2EXTPROC glad_glShaderOp2EXT;
+#define glShaderOp2EXT glad_glShaderOp2EXT
+typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC)(GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);
+GLAPI PFNGLSHADEROP3EXTPROC glad_glShaderOp3EXT;
+#define glShaderOp3EXT glad_glShaderOp3EXT
+typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC)(GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+GLAPI PFNGLSWIZZLEEXTPROC glad_glSwizzleEXT;
+#define glSwizzleEXT glad_glSwizzleEXT
+typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC)(GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+GLAPI PFNGLWRITEMASKEXTPROC glad_glWriteMaskEXT;
+#define glWriteMaskEXT glad_glWriteMaskEXT
+typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC)(GLuint res, GLuint src, GLuint num);
+GLAPI PFNGLINSERTCOMPONENTEXTPROC glad_glInsertComponentEXT;
+#define glInsertComponentEXT glad_glInsertComponentEXT
+typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC)(GLuint res, GLuint src, GLuint num);
+GLAPI PFNGLEXTRACTCOMPONENTEXTPROC glad_glExtractComponentEXT;
+#define glExtractComponentEXT glad_glExtractComponentEXT
+typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC)(GLenum datatype, GLenum storagetype, GLenum range, GLuint components);
+GLAPI PFNGLGENSYMBOLSEXTPROC glad_glGenSymbolsEXT;
+#define glGenSymbolsEXT glad_glGenSymbolsEXT
+typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC)(GLuint id, GLenum type, const void* addr);
+GLAPI PFNGLSETINVARIANTEXTPROC glad_glSetInvariantEXT;
+#define glSetInvariantEXT glad_glSetInvariantEXT
+typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC)(GLuint id, GLenum type, const void* addr);
+GLAPI PFNGLSETLOCALCONSTANTEXTPROC glad_glSetLocalConstantEXT;
+#define glSetLocalConstantEXT glad_glSetLocalConstantEXT
+typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC)(GLuint id, const GLbyte* addr);
+GLAPI PFNGLVARIANTBVEXTPROC glad_glVariantbvEXT;
+#define glVariantbvEXT glad_glVariantbvEXT
+typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC)(GLuint id, const GLshort* addr);
+GLAPI PFNGLVARIANTSVEXTPROC glad_glVariantsvEXT;
+#define glVariantsvEXT glad_glVariantsvEXT
+typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC)(GLuint id, const GLint* addr);
+GLAPI PFNGLVARIANTIVEXTPROC glad_glVariantivEXT;
+#define glVariantivEXT glad_glVariantivEXT
+typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC)(GLuint id, const GLfloat* addr);
+GLAPI PFNGLVARIANTFVEXTPROC glad_glVariantfvEXT;
+#define glVariantfvEXT glad_glVariantfvEXT
+typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC)(GLuint id, const GLdouble* addr);
+GLAPI PFNGLVARIANTDVEXTPROC glad_glVariantdvEXT;
+#define glVariantdvEXT glad_glVariantdvEXT
+typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC)(GLuint id, const GLubyte* addr);
+GLAPI PFNGLVARIANTUBVEXTPROC glad_glVariantubvEXT;
+#define glVariantubvEXT glad_glVariantubvEXT
+typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC)(GLuint id, const GLushort* addr);
+GLAPI PFNGLVARIANTUSVEXTPROC glad_glVariantusvEXT;
+#define glVariantusvEXT glad_glVariantusvEXT
+typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC)(GLuint id, const GLuint* addr);
+GLAPI PFNGLVARIANTUIVEXTPROC glad_glVariantuivEXT;
+#define glVariantuivEXT glad_glVariantuivEXT
+typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC)(GLuint id, GLenum type, GLuint stride, const void* addr);
+GLAPI PFNGLVARIANTPOINTEREXTPROC glad_glVariantPointerEXT;
+#define glVariantPointerEXT glad_glVariantPointerEXT
+typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC)(GLuint id);
+GLAPI PFNGLENABLEVARIANTCLIENTSTATEEXTPROC glad_glEnableVariantClientStateEXT;
+#define glEnableVariantClientStateEXT glad_glEnableVariantClientStateEXT
+typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC)(GLuint id);
+GLAPI PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC glad_glDisableVariantClientStateEXT;
+#define glDisableVariantClientStateEXT glad_glDisableVariantClientStateEXT
+typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC)(GLenum light, GLenum value);
+GLAPI PFNGLBINDLIGHTPARAMETEREXTPROC glad_glBindLightParameterEXT;
+#define glBindLightParameterEXT glad_glBindLightParameterEXT
+typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC)(GLenum face, GLenum value);
+GLAPI PFNGLBINDMATERIALPARAMETEREXTPROC glad_glBindMaterialParameterEXT;
+#define glBindMaterialParameterEXT glad_glBindMaterialParameterEXT
+typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC)(GLenum unit, GLenum coord, GLenum value);
+GLAPI PFNGLBINDTEXGENPARAMETEREXTPROC glad_glBindTexGenParameterEXT;
+#define glBindTexGenParameterEXT glad_glBindTexGenParameterEXT
+typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC)(GLenum unit, GLenum value);
+GLAPI PFNGLBINDTEXTUREUNITPARAMETEREXTPROC glad_glBindTextureUnitParameterEXT;
+#define glBindTextureUnitParameterEXT glad_glBindTextureUnitParameterEXT
+typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC)(GLenum value);
+GLAPI PFNGLBINDPARAMETEREXTPROC glad_glBindParameterEXT;
+#define glBindParameterEXT glad_glBindParameterEXT
+typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC)(GLuint id, GLenum cap);
+GLAPI PFNGLISVARIANTENABLEDEXTPROC glad_glIsVariantEnabledEXT;
+#define glIsVariantEnabledEXT glad_glIsVariantEnabledEXT
+typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC)(GLuint id, GLenum value, GLboolean* data);
+GLAPI PFNGLGETVARIANTBOOLEANVEXTPROC glad_glGetVariantBooleanvEXT;
+#define glGetVariantBooleanvEXT glad_glGetVariantBooleanvEXT
+typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC)(GLuint id, GLenum value, GLint* data);
+GLAPI PFNGLGETVARIANTINTEGERVEXTPROC glad_glGetVariantIntegervEXT;
+#define glGetVariantIntegervEXT glad_glGetVariantIntegervEXT
+typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC)(GLuint id, GLenum value, GLfloat* data);
+GLAPI PFNGLGETVARIANTFLOATVEXTPROC glad_glGetVariantFloatvEXT;
+#define glGetVariantFloatvEXT glad_glGetVariantFloatvEXT
+typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC)(GLuint id, GLenum value, void** data);
+GLAPI PFNGLGETVARIANTPOINTERVEXTPROC glad_glGetVariantPointervEXT;
+#define glGetVariantPointervEXT glad_glGetVariantPointervEXT
+typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC)(GLuint id, GLenum value, GLboolean* data);
+GLAPI PFNGLGETINVARIANTBOOLEANVEXTPROC glad_glGetInvariantBooleanvEXT;
+#define glGetInvariantBooleanvEXT glad_glGetInvariantBooleanvEXT
+typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC)(GLuint id, GLenum value, GLint* data);
+GLAPI PFNGLGETINVARIANTINTEGERVEXTPROC glad_glGetInvariantIntegervEXT;
+#define glGetInvariantIntegervEXT glad_glGetInvariantIntegervEXT
+typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC)(GLuint id, GLenum value, GLfloat* data);
+GLAPI PFNGLGETINVARIANTFLOATVEXTPROC glad_glGetInvariantFloatvEXT;
+#define glGetInvariantFloatvEXT glad_glGetInvariantFloatvEXT
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC)(GLuint id, GLenum value, GLboolean* data);
+GLAPI PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC glad_glGetLocalConstantBooleanvEXT;
+#define glGetLocalConstantBooleanvEXT glad_glGetLocalConstantBooleanvEXT
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC)(GLuint id, GLenum value, GLint* data);
+GLAPI PFNGLGETLOCALCONSTANTINTEGERVEXTPROC glad_glGetLocalConstantIntegervEXT;
+#define glGetLocalConstantIntegervEXT glad_glGetLocalConstantIntegervEXT
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC)(GLuint id, GLenum value, GLfloat* data);
+GLAPI PFNGLGETLOCALCONSTANTFLOATVEXTPROC glad_glGetLocalConstantFloatvEXT;
+#define glGetLocalConstantFloatvEXT glad_glGetLocalConstantFloatvEXT
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// IMPLEMENTATION SECTION
+//
+
+#ifdef GLAD_IMPLEMENTATION
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct gladGLversionStruct GLVersion;
+
+#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)
+#define _GLAD_IS_SOME_NEW_VERSION 1
+#endif
+
+static int max_loaded_major;
+static int max_loaded_minor;
+
+static const char *exts = NULL;
+static int num_exts_i = 0;
+static const char **exts_i = NULL;
+
+static int get_exts(void) {
+#ifdef _GLAD_IS_SOME_NEW_VERSION
+ if(max_loaded_major < 3) {
+#endif
+ exts = (const char *)glGetString(GL_EXTENSIONS);
+#ifdef _GLAD_IS_SOME_NEW_VERSION
+ } else {
+ int index;
+
+ num_exts_i = 0;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i);
+ if (num_exts_i > 0) {
+ exts_i = (const char **)realloc((void *)exts_i, num_exts_i * sizeof *exts_i);
+ }
+
+ if (exts_i == NULL) {
+ return 0;
+ }
+
+ for(index = 0; index < num_exts_i; index++) {
+ exts_i[index] = (const char*)glGetStringi(GL_EXTENSIONS, index);
+ }
+ }
+#endif
+ return 1;
+}
+
+static void free_exts(void) {
+ if (exts_i != NULL) {
+ free((char **)exts_i);
+ exts_i = NULL;
+ }
+}
+
+static int has_ext(const char *ext) {
+#ifdef _GLAD_IS_SOME_NEW_VERSION
+ if(max_loaded_major < 3) {
+#endif
+ const char *extensions;
+ const char *loc;
+ const char *terminator;
+ extensions = exts;
+ if(extensions == NULL || ext == NULL) {
+ return 0;
+ }
+
+ while(1) {
+ loc = strstr(extensions, ext);
+ if(loc == NULL) {
+ return 0;
+ }
+
+ terminator = loc + strlen(ext);
+ if((loc == extensions || *(loc - 1) == ' ') &&
+ (*terminator == ' ' || *terminator == '\0')) {
+ return 1;
+ }
+ extensions = terminator;
+ }
+#ifdef _GLAD_IS_SOME_NEW_VERSION
+ } else {
+ int index;
+
+ for(index = 0; index < num_exts_i; index++) {
+ const char *e = exts_i[index];
+
+ if(strcmp(e, ext) == 0) {
+ return 1;
+ }
+ }
+ }
+#endif
+
+ return 0;
+}
+int GLAD_GL_VERSION_1_0;
+int GLAD_GL_VERSION_1_1;
+int GLAD_GL_VERSION_1_2;
+int GLAD_GL_VERSION_1_3;
+int GLAD_GL_VERSION_1_4;
+int GLAD_GL_VERSION_1_5;
+int GLAD_GL_VERSION_2_0;
+int GLAD_GL_VERSION_2_1;
+int GLAD_GL_VERSION_3_0;
+int GLAD_GL_VERSION_3_1;
+int GLAD_GL_VERSION_3_2;
+int GLAD_GL_VERSION_3_3;
+PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D;
+PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui;
+PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate;
+PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer;
+PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D;
+PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv;
+PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv;
+PFNGLBINDSAMPLERPROC glad_glBindSampler;
+PFNGLLINEWIDTHPROC glad_glLineWidth;
+PFNGLCOLORP3UIVPROC glad_glColorP3uiv;
+PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v;
+PFNGLCOMPILESHADERPROC glad_glCompileShader;
+PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying;
+PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer;
+PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui;
+PFNGLVERTEXP4UIPROC glad_glVertexP4ui;
+PFNGLENABLEIPROC glad_glEnablei;
+PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui;
+PFNGLCREATESHADERPROC glad_glCreateShader;
+PFNGLISBUFFERPROC glad_glIsBuffer;
+PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv;
+PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers;
+PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D;
+PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D;
+PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f;
+PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate;
+PFNGLHINTPROC glad_glHint;
+PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s;
+PFNGLSAMPLEMASKIPROC glad_glSampleMaski;
+PFNGLVERTEXP2UIPROC glad_glVertexP2ui;
+PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv;
+PFNGLPOINTSIZEPROC glad_glPointSize;
+PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv;
+PFNGLDELETEPROGRAMPROC glad_glDeleteProgram;
+PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv;
+PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage;
+PFNGLWAITSYNCPROC glad_glWaitSync;
+PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv;
+PFNGLUNIFORM3IPROC glad_glUniform3i;
+PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv;
+PFNGLUNIFORM3FPROC glad_glUniform3f;
+PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv;
+PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv;
+PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui;
+PFNGLCOLORMASKIPROC glad_glColorMaski;
+PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi;
+PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays;
+PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui;
+PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv;
+PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex;
+PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv;
+PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv;
+PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui;
+PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers;
+PFNGLDRAWARRAYSPROC glad_glDrawArrays;
+PFNGLUNIFORM1UIPROC glad_glUniform1ui;
+PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i;
+PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui;
+PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d;
+PFNGLCLEARPROC glad_glClear;
+PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName;
+PFNGLISENABLEDPROC glad_glIsEnabled;
+PFNGLSTENCILOPPROC glad_glStencilOp;
+PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D;
+PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv;
+PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub;
+PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation;
+PFNGLTEXIMAGE1DPROC glad_glTexImage1D;
+PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv;
+PFNGLGETTEXIMAGEPROC glad_glGetTexImage;
+PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v;
+PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers;
+PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders;
+PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer;
+PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays;
+PFNGLISVERTEXARRAYPROC glad_glIsVertexArray;
+PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray;
+PFNGLGETQUERYIVPROC glad_glGetQueryiv;
+PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv;
+PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices;
+PFNGLISSHADERPROC glad_glIsShader;
+PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv;
+PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv;
+PFNGLENABLEPROC glad_glEnable;
+PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv;
+PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation;
+PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv;
+PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv;
+PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui;
+PFNGLGETUNIFORMFVPROC glad_glGetUniformfv;
+PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv;
+PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv;
+PFNGLDRAWBUFFERPROC glad_glDrawBuffer;
+PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv;
+PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced;
+PFNGLFLUSHPROC glad_glFlush;
+PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv;
+PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv;
+PFNGLFENCESYNCPROC glad_glFenceSync;
+PFNGLCOLORP3UIPROC glad_glColorP3ui;
+PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv;
+PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender;
+PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv;
+PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv;
+PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate;
+PFNGLGENSAMPLERSPROC glad_glGenSamplers;
+PFNGLCLAMPCOLORPROC glad_glClampColor;
+PFNGLUNIFORM4IVPROC glad_glUniform4iv;
+PFNGLCLEARSTENCILPROC glad_glClearStencil;
+PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv;
+PFNGLGENTEXTURESPROC glad_glGenTextures;
+PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv;
+PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv;
+PFNGLISSYNCPROC glad_glIsSync;
+PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName;
+PFNGLUNIFORM2IPROC glad_glUniform2i;
+PFNGLUNIFORM2FPROC glad_glUniform2f;
+PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui;
+PFNGLGETPROGRAMIVPROC glad_glGetProgramiv;
+PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer;
+PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer;
+PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange;
+PFNGLGENQUERIESPROC glad_glGenQueries;
+PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui;
+PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D;
+PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v;
+PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers;
+PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D;
+PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer;
+PFNGLISENABLEDIPROC glad_glIsEnabledi;
+PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui;
+PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed;
+PFNGLUNIFORM2IVPROC glad_glUniform2iv;
+PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv;
+PFNGLUNIFORM4UIVPROC glad_glUniform4uiv;
+PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D;
+PFNGLGETSHADERIVPROC glad_glGetShaderiv;
+PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation;
+PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset;
+PFNGLGETDOUBLEVPROC glad_glGetDoublev;
+PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d;
+PFNGLGETUNIFORMIVPROC glad_glGetUniformiv;
+PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv;
+PFNGLUNIFORM3FVPROC glad_glUniform3fv;
+PFNGLDEPTHRANGEPROC glad_glDepthRange;
+PFNGLMAPBUFFERPROC glad_glMapBuffer;
+PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D;
+PFNGLDELETESYNCPROC glad_glDeleteSync;
+PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D;
+PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv;
+PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements;
+PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv;
+PFNGLUNIFORM3IVPROC glad_glUniform3iv;
+PFNGLPOLYGONMODEPROC glad_glPolygonMode;
+PFNGLDRAWBUFFERSPROC glad_glDrawBuffers;
+PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv;
+PFNGLUSEPROGRAMPROC glad_glUseProgram;
+PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog;
+PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray;
+PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;
+PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv;
+PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex;
+PFNGLUNIFORM2UIVPROC glad_glUniform2uiv;
+PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D;
+PFNGLFINISHPROC glad_glFinish;
+PFNGLDELETESHADERPROC glad_glDeleteShader;
+PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv;
+PFNGLVIEWPORTPROC glad_glViewport;
+PFNGLUNIFORM1UIVPROC glad_glUniform1uiv;
+PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings;
+PFNGLUNIFORM2UIPROC glad_glUniform2ui;
+PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i;
+PFNGLCLEARDEPTHPROC glad_glClearDepth;
+PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv;
+PFNGLTEXPARAMETERFPROC glad_glTexParameterf;
+PFNGLTEXPARAMETERIPROC glad_glTexParameteri;
+PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource;
+PFNGLTEXBUFFERPROC glad_glTexBuffer;
+PFNGLPIXELSTOREIPROC glad_glPixelStorei;
+PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram;
+PFNGLPIXELSTOREFPROC glad_glPixelStoref;
+PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v;
+PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv;
+PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv;
+PFNGLLINKPROGRAMPROC glad_glLinkProgram;
+PFNGLBINDTEXTUREPROC glad_glBindTexture;
+PFNGLGETSTRINGPROC glad_glGetString;
+PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv;
+PFNGLDETACHSHADERPROC glad_glDetachShader;
+PFNGLENDQUERYPROC glad_glEndQuery;
+PFNGLNORMALP3UIPROC glad_glNormalP3ui;
+PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui;
+PFNGLDELETETEXTURESPROC glad_glDeleteTextures;
+PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate;
+PFNGLDELETEQUERIESPROC glad_glDeleteQueries;
+PFNGLNORMALP3UIVPROC glad_glNormalP3uiv;
+PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f;
+PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d;
+PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv;
+PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s;
+PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex;
+PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage;
+PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri;
+PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf;
+PFNGLUNIFORM1FPROC glad_glUniform1f;
+PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv;
+PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage;
+PFNGLUNIFORM1IPROC glad_glUniform1i;
+PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib;
+PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D;
+PFNGLDISABLEPROC glad_glDisable;
+PFNGLLOGICOPPROC glad_glLogicOp;
+PFNGLUNIFORM4UIPROC glad_glUniform4ui;
+PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer;
+PFNGLCULLFACEPROC glad_glCullFace;
+PFNGLGETSTRINGIPROC glad_glGetStringi;
+PFNGLATTACHSHADERPROC glad_glAttachShader;
+PFNGLQUERYCOUNTERPROC glad_glQueryCounter;
+PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex;
+PFNGLDRAWELEMENTSPROC glad_glDrawElements;
+PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv;
+PFNGLUNIFORM1IVPROC glad_glUniform1iv;
+PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv;
+PFNGLREADBUFFERPROC glad_glReadBuffer;
+PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv;
+PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced;
+PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap;
+PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv;
+PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f;
+PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv;
+PFNGLPOINTPARAMETERIPROC glad_glPointParameteri;
+PFNGLBLENDCOLORPROC glad_glBlendColor;
+PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv;
+PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer;
+PFNGLPOINTPARAMETERFPROC glad_glPointParameterf;
+PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s;
+PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer;
+PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv;
+PFNGLISPROGRAMPROC glad_glIsProgram;
+PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv;
+PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv;
+PFNGLUNIFORM4IPROC glad_glUniform4i;
+PFNGLACTIVETEXTUREPROC glad_glActiveTexture;
+PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray;
+PFNGLREADPIXELSPROC glad_glReadPixels;
+PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv;
+PFNGLUNIFORM4FPROC glad_glUniform4f;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample;
+PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv;
+PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex;
+PFNGLSTENCILFUNCPROC glad_glStencilFunc;
+PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding;
+PFNGLCOLORP4UIPROC glad_glColorP4ui;
+PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv;
+PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog;
+PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i;
+PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData;
+PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate;
+PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui;
+PFNGLGENBUFFERSPROC glad_glGenBuffers;
+PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv;
+PFNGLBLENDFUNCPROC glad_glBlendFunc;
+PFNGLCREATEPROGRAMPROC glad_glCreateProgram;
+PFNGLTEXIMAGE3DPROC glad_glTexImage3D;
+PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer;
+PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex;
+PFNGLGETINTEGER64VPROC glad_glGetInteger64v;
+PFNGLSCISSORPROC glad_glScissor;
+PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv;
+PFNGLGETBOOLEANVPROC glad_glGetBooleanv;
+PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv;
+PFNGLUNIFORM3UIVPROC glad_glUniform3uiv;
+PFNGLCLEARCOLORPROC glad_glClearColor;
+PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv;
+PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv;
+PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v;
+PFNGLCOLORP4UIVPROC glad_glColorP4uiv;
+PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv;
+PFNGLUNIFORM3UIPROC glad_glUniform3ui;
+PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv;
+PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv;
+PFNGLUNIFORM2FVPROC glad_glUniform2fv;
+PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv;
+PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange;
+PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv;
+PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv;
+PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv;
+PFNGLDEPTHFUNCPROC glad_glDepthFunc;
+PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D;
+PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv;
+PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv;
+PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui;
+PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync;
+PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui;
+PFNGLCOLORMASKPROC glad_glColorMask;
+PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv;
+PFNGLBLENDEQUATIONPROC glad_glBlendEquation;
+PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation;
+PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback;
+PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv;
+PFNGLUNIFORM4FVPROC glad_glUniform4fv;
+PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback;
+PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv;
+PFNGLISSAMPLERPROC glad_glIsSampler;
+PFNGLVERTEXP3UIPROC glad_glVertexP3ui;
+PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor;
+PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D;
+PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D;
+PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex;
+PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus;
+PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender;
+PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv;
+PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation;
+PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv;
+PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv;
+PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements;
+PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv;
+PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase;
+PFNGLBUFFERSUBDATAPROC glad_glBufferSubData;
+PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv;
+PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange;
+PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture;
+PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays;
+PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv;
+PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv;
+PFNGLDISABLEIPROC glad_glDisablei;
+PFNGLSHADERSOURCEPROC glad_glShaderSource;
+PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers;
+PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv;
+PFNGLGETSYNCIVPROC glad_glGetSynciv;
+PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv;
+PFNGLBEGINQUERYPROC glad_glBeginQuery;
+PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv;
+PFNGLBINDBUFFERPROC glad_glBindBuffer;
+PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv;
+PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv;
+PFNGLBUFFERDATAPROC glad_glBufferData;
+PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv;
+PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui;
+PFNGLGETERRORPROC glad_glGetError;
+PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui;
+PFNGLGETFLOATVPROC glad_glGetFloatv;
+PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D;
+PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv;
+PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv;
+PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i;
+PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv;
+PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
+PFNGLGETINTEGERVPROC glad_glGetIntegerv;
+PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv;
+PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D;
+PFNGLISQUERYPROC glad_glIsQuery;
+PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv;
+PFNGLTEXIMAGE2DPROC glad_glTexImage2D;
+PFNGLSTENCILMASKPROC glad_glStencilMask;
+PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv;
+PFNGLISTEXTUREPROC glad_glIsTexture;
+PFNGLUNIFORM1FVPROC glad_glUniform1fv;
+PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv;
+PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv;
+PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv;
+PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData;
+PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv;
+PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d;
+PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f;
+PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv;
+PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v;
+PFNGLDEPTHMASKPROC glad_glDepthMask;
+PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s;
+PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample;
+PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex;
+PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample;
+PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform;
+PFNGLFRONTFACEPROC glad_glFrontFace;
+int GLAD_GL_ARB_texture_compression;
+int GLAD_GL_ARB_texture_swizzle;
+int GLAD_GL_ATI_fragment_shader;
+int GLAD_GL_EXT_texture_sRGB;
+int GLAD_GL_ARB_explicit_attrib_location;
+int GLAD_GL_ARB_ES3_compatibility;
+int GLAD_GL_EXT_blend_color;
+int GLAD_GL_EXT_framebuffer_sRGB;
+int GLAD_GL_EXT_index_array_formats;
+int GLAD_GL_ARB_vertex_shader;
+int GLAD_GL_ARB_vertex_attrib_binding;
+int GLAD_GL_ARB_vertex_program;
+int GLAD_GL_EXT_texture_compression_s3tc;
+int GLAD_GL_EXT_texture_swizzle;
+int GLAD_GL_ARB_texture_multisample;
+int GLAD_GL_ARB_texture_rg;
+int GLAD_GL_ARB_texture_float;
+int GLAD_GL_ARB_compressed_texture_pixel_storage;
+int GLAD_GL_ARB_framebuffer_sRGB;
+int GLAD_GL_ARB_vertex_array_object;
+int GLAD_GL_ARB_depth_clamp;
+int GLAD_GL_ARB_fragment_shader;
+int GLAD_GL_ATI_vertex_array_object;
+int GLAD_GL_ARB_vertex_buffer_object;
+int GLAD_GL_ARB_fragment_program;
+int GLAD_GL_EXT_framebuffer_multisample;
+int GLAD_GL_ARB_framebuffer_object;
+int GLAD_GL_ARB_draw_buffers_blend;
+int GLAD_GL_EXT_vertex_shader;
+int GLAD_GL_EXT_blend_func_separate;
+int GLAD_GL_ARB_texture_non_power_of_two;
+int GLAD_GL_EXT_texture;
+int GLAD_GL_ARB_buffer_storage;
+int GLAD_GL_ARB_explicit_uniform_location;
+int GLAD_GL_EXT_framebuffer_object;
+int GLAD_GL_EXT_framebuffer_multisample_blit_scaled;
+int GLAD_GL_AMD_debug_output;
+int GLAD_GL_ARB_depth_buffer_float;
+int GLAD_GL_ARB_multisample;
+int GLAD_GL_ARB_compatibility;
+int GLAD_GL_ARB_depth_texture;
+int GLAD_GL_ARB_sample_locations;
+int GLAD_GL_ARB_ES2_compatibility;
+int GLAD_GL_AMD_query_buffer_object;
+int GLAD_GL_EXT_framebuffer_blit;
+int GLAD_GL_EXT_vertex_array;
+int GLAD_GL_ARB_draw_buffers;
+int GLAD_GL_EXT_blend_equation_separate;
+int GLAD_GL_ATI_element_array;
+int GLAD_GL_ARB_debug_output;
+int GLAD_GL_ARB_uniform_buffer_object;
+PFNGLDEBUGMESSAGEENABLEAMDPROC glad_glDebugMessageEnableAMD;
+PFNGLDEBUGMESSAGEINSERTAMDPROC glad_glDebugMessageInsertAMD;
+PFNGLDEBUGMESSAGECALLBACKAMDPROC glad_glDebugMessageCallbackAMD;
+PFNGLGETDEBUGMESSAGELOGAMDPROC glad_glGetDebugMessageLogAMD;
+PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler;
+PFNGLSHADERBINARYPROC glad_glShaderBinary;
+PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat;
+PFNGLDEPTHRANGEFPROC glad_glDepthRangef;
+PFNGLCLEARDEPTHFPROC glad_glClearDepthf;
+PFNGLBUFFERSTORAGEPROC glad_glBufferStorage;
+PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB;
+PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB;
+PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB;
+PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB;
+PFNGLDRAWBUFFERSARBPROC glad_glDrawBuffersARB;
+PFNGLBLENDEQUATIONIARBPROC glad_glBlendEquationiARB;
+PFNGLBLENDEQUATIONSEPARATEIARBPROC glad_glBlendEquationSeparateiARB;
+PFNGLBLENDFUNCIARBPROC glad_glBlendFunciARB;
+PFNGLBLENDFUNCSEPARATEIARBPROC glad_glBlendFuncSeparateiARB;
+PFNGLPROGRAMSTRINGARBPROC glad_glProgramStringARB;
+PFNGLBINDPROGRAMARBPROC glad_glBindProgramARB;
+PFNGLDELETEPROGRAMSARBPROC glad_glDeleteProgramsARB;
+PFNGLGENPROGRAMSARBPROC glad_glGenProgramsARB;
+PFNGLPROGRAMENVPARAMETER4DARBPROC glad_glProgramEnvParameter4dARB;
+PFNGLPROGRAMENVPARAMETER4DVARBPROC glad_glProgramEnvParameter4dvARB;
+PFNGLPROGRAMENVPARAMETER4FARBPROC glad_glProgramEnvParameter4fARB;
+PFNGLPROGRAMENVPARAMETER4FVARBPROC glad_glProgramEnvParameter4fvARB;
+PFNGLPROGRAMLOCALPARAMETER4DARBPROC glad_glProgramLocalParameter4dARB;
+PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glad_glProgramLocalParameter4dvARB;
+PFNGLPROGRAMLOCALPARAMETER4FARBPROC glad_glProgramLocalParameter4fARB;
+PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glad_glProgramLocalParameter4fvARB;
+PFNGLGETPROGRAMENVPARAMETERDVARBPROC glad_glGetProgramEnvParameterdvARB;
+PFNGLGETPROGRAMENVPARAMETERFVARBPROC glad_glGetProgramEnvParameterfvARB;
+PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glad_glGetProgramLocalParameterdvARB;
+PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glad_glGetProgramLocalParameterfvARB;
+PFNGLGETPROGRAMIVARBPROC glad_glGetProgramivARB;
+PFNGLGETPROGRAMSTRINGARBPROC glad_glGetProgramStringARB;
+PFNGLISPROGRAMARBPROC glad_glIsProgramARB;
+PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB;
+PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glFramebufferSampleLocationsfvARB;
+PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glNamedFramebufferSampleLocationsfvARB;
+PFNGLEVALUATEDEPTHVALUESARBPROC glad_glEvaluateDepthValuesARB;
+PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glad_glCompressedTexImage3DARB;
+PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glad_glCompressedTexImage2DARB;
+PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glad_glCompressedTexImage1DARB;
+PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glad_glCompressedTexSubImage3DARB;
+PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glad_glCompressedTexSubImage2DARB;
+PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glad_glCompressedTexSubImage1DARB;
+PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glad_glGetCompressedTexImageARB;
+PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer;
+PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat;
+PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat;
+PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat;
+PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding;
+PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor;
+PFNGLBINDBUFFERARBPROC glad_glBindBufferARB;
+PFNGLDELETEBUFFERSARBPROC glad_glDeleteBuffersARB;
+PFNGLGENBUFFERSARBPROC glad_glGenBuffersARB;
+PFNGLISBUFFERARBPROC glad_glIsBufferARB;
+PFNGLBUFFERDATAARBPROC glad_glBufferDataARB;
+PFNGLBUFFERSUBDATAARBPROC glad_glBufferSubDataARB;
+PFNGLGETBUFFERSUBDATAARBPROC glad_glGetBufferSubDataARB;
+PFNGLMAPBUFFERARBPROC glad_glMapBufferARB;
+PFNGLUNMAPBUFFERARBPROC glad_glUnmapBufferARB;
+PFNGLGETBUFFERPARAMETERIVARBPROC glad_glGetBufferParameterivARB;
+PFNGLGETBUFFERPOINTERVARBPROC glad_glGetBufferPointervARB;
+PFNGLVERTEXATTRIB1DARBPROC glad_glVertexAttrib1dARB;
+PFNGLVERTEXATTRIB1DVARBPROC glad_glVertexAttrib1dvARB;
+PFNGLVERTEXATTRIB1FARBPROC glad_glVertexAttrib1fARB;
+PFNGLVERTEXATTRIB1FVARBPROC glad_glVertexAttrib1fvARB;
+PFNGLVERTEXATTRIB1SARBPROC glad_glVertexAttrib1sARB;
+PFNGLVERTEXATTRIB1SVARBPROC glad_glVertexAttrib1svARB;
+PFNGLVERTEXATTRIB2DARBPROC glad_glVertexAttrib2dARB;
+PFNGLVERTEXATTRIB2DVARBPROC glad_glVertexAttrib2dvARB;
+PFNGLVERTEXATTRIB2FARBPROC glad_glVertexAttrib2fARB;
+PFNGLVERTEXATTRIB2FVARBPROC glad_glVertexAttrib2fvARB;
+PFNGLVERTEXATTRIB2SARBPROC glad_glVertexAttrib2sARB;
+PFNGLVERTEXATTRIB2SVARBPROC glad_glVertexAttrib2svARB;
+PFNGLVERTEXATTRIB3DARBPROC glad_glVertexAttrib3dARB;
+PFNGLVERTEXATTRIB3DVARBPROC glad_glVertexAttrib3dvARB;
+PFNGLVERTEXATTRIB3FARBPROC glad_glVertexAttrib3fARB;
+PFNGLVERTEXATTRIB3FVARBPROC glad_glVertexAttrib3fvARB;
+PFNGLVERTEXATTRIB3SARBPROC glad_glVertexAttrib3sARB;
+PFNGLVERTEXATTRIB3SVARBPROC glad_glVertexAttrib3svARB;
+PFNGLVERTEXATTRIB4NBVARBPROC glad_glVertexAttrib4NbvARB;
+PFNGLVERTEXATTRIB4NIVARBPROC glad_glVertexAttrib4NivARB;
+PFNGLVERTEXATTRIB4NSVARBPROC glad_glVertexAttrib4NsvARB;
+PFNGLVERTEXATTRIB4NUBARBPROC glad_glVertexAttrib4NubARB;
+PFNGLVERTEXATTRIB4NUBVARBPROC glad_glVertexAttrib4NubvARB;
+PFNGLVERTEXATTRIB4NUIVARBPROC glad_glVertexAttrib4NuivARB;
+PFNGLVERTEXATTRIB4NUSVARBPROC glad_glVertexAttrib4NusvARB;
+PFNGLVERTEXATTRIB4BVARBPROC glad_glVertexAttrib4bvARB;
+PFNGLVERTEXATTRIB4DARBPROC glad_glVertexAttrib4dARB;
+PFNGLVERTEXATTRIB4DVARBPROC glad_glVertexAttrib4dvARB;
+PFNGLVERTEXATTRIB4FARBPROC glad_glVertexAttrib4fARB;
+PFNGLVERTEXATTRIB4FVARBPROC glad_glVertexAttrib4fvARB;
+PFNGLVERTEXATTRIB4IVARBPROC glad_glVertexAttrib4ivARB;
+PFNGLVERTEXATTRIB4SARBPROC glad_glVertexAttrib4sARB;
+PFNGLVERTEXATTRIB4SVARBPROC glad_glVertexAttrib4svARB;
+PFNGLVERTEXATTRIB4UBVARBPROC glad_glVertexAttrib4ubvARB;
+PFNGLVERTEXATTRIB4UIVARBPROC glad_glVertexAttrib4uivARB;
+PFNGLVERTEXATTRIB4USVARBPROC glad_glVertexAttrib4usvARB;
+PFNGLVERTEXATTRIBPOINTERARBPROC glad_glVertexAttribPointerARB;
+PFNGLENABLEVERTEXATTRIBARRAYARBPROC glad_glEnableVertexAttribArrayARB;
+PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glad_glDisableVertexAttribArrayARB;
+PFNGLGETVERTEXATTRIBDVARBPROC glad_glGetVertexAttribdvARB;
+PFNGLGETVERTEXATTRIBFVARBPROC glad_glGetVertexAttribfvARB;
+PFNGLGETVERTEXATTRIBIVARBPROC glad_glGetVertexAttribivARB;
+PFNGLGETVERTEXATTRIBPOINTERVARBPROC glad_glGetVertexAttribPointervARB;
+PFNGLBINDATTRIBLOCATIONARBPROC glad_glBindAttribLocationARB;
+PFNGLGETACTIVEATTRIBARBPROC glad_glGetActiveAttribARB;
+PFNGLGETATTRIBLOCATIONARBPROC glad_glGetAttribLocationARB;
+PFNGLELEMENTPOINTERATIPROC glad_glElementPointerATI;
+PFNGLDRAWELEMENTARRAYATIPROC glad_glDrawElementArrayATI;
+PFNGLDRAWRANGEELEMENTARRAYATIPROC glad_glDrawRangeElementArrayATI;
+PFNGLGENFRAGMENTSHADERSATIPROC glad_glGenFragmentShadersATI;
+PFNGLBINDFRAGMENTSHADERATIPROC glad_glBindFragmentShaderATI;
+PFNGLDELETEFRAGMENTSHADERATIPROC glad_glDeleteFragmentShaderATI;
+PFNGLBEGINFRAGMENTSHADERATIPROC glad_glBeginFragmentShaderATI;
+PFNGLENDFRAGMENTSHADERATIPROC glad_glEndFragmentShaderATI;
+PFNGLPASSTEXCOORDATIPROC glad_glPassTexCoordATI;
+PFNGLSAMPLEMAPATIPROC glad_glSampleMapATI;
+PFNGLCOLORFRAGMENTOP1ATIPROC glad_glColorFragmentOp1ATI;
+PFNGLCOLORFRAGMENTOP2ATIPROC glad_glColorFragmentOp2ATI;
+PFNGLCOLORFRAGMENTOP3ATIPROC glad_glColorFragmentOp3ATI;
+PFNGLALPHAFRAGMENTOP1ATIPROC glad_glAlphaFragmentOp1ATI;
+PFNGLALPHAFRAGMENTOP2ATIPROC glad_glAlphaFragmentOp2ATI;
+PFNGLALPHAFRAGMENTOP3ATIPROC glad_glAlphaFragmentOp3ATI;
+PFNGLSETFRAGMENTSHADERCONSTANTATIPROC glad_glSetFragmentShaderConstantATI;
+PFNGLNEWOBJECTBUFFERATIPROC glad_glNewObjectBufferATI;
+PFNGLISOBJECTBUFFERATIPROC glad_glIsObjectBufferATI;
+PFNGLUPDATEOBJECTBUFFERATIPROC glad_glUpdateObjectBufferATI;
+PFNGLGETOBJECTBUFFERFVATIPROC glad_glGetObjectBufferfvATI;
+PFNGLGETOBJECTBUFFERIVATIPROC glad_glGetObjectBufferivATI;
+PFNGLFREEOBJECTBUFFERATIPROC glad_glFreeObjectBufferATI;
+PFNGLARRAYOBJECTATIPROC glad_glArrayObjectATI;
+PFNGLGETARRAYOBJECTFVATIPROC glad_glGetArrayObjectfvATI;
+PFNGLGETARRAYOBJECTIVATIPROC glad_glGetArrayObjectivATI;
+PFNGLVARIANTARRAYOBJECTATIPROC glad_glVariantArrayObjectATI;
+PFNGLGETVARIANTARRAYOBJECTFVATIPROC glad_glGetVariantArrayObjectfvATI;
+PFNGLGETVARIANTARRAYOBJECTIVATIPROC glad_glGetVariantArrayObjectivATI;
+PFNGLBLENDCOLOREXTPROC glad_glBlendColorEXT;
+PFNGLBLENDEQUATIONSEPARATEEXTPROC glad_glBlendEquationSeparateEXT;
+PFNGLBLENDFUNCSEPARATEEXTPROC glad_glBlendFuncSeparateEXT;
+PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT;
+PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT;
+PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT;
+PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT;
+PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT;
+PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT;
+PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT;
+PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT;
+PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT;
+PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT;
+PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT;
+PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT;
+PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT;
+PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT;
+PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT;
+PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT;
+PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT;
+PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT;
+PFNGLARRAYELEMENTEXTPROC glad_glArrayElementEXT;
+PFNGLCOLORPOINTEREXTPROC glad_glColorPointerEXT;
+PFNGLDRAWARRAYSEXTPROC glad_glDrawArraysEXT;
+PFNGLEDGEFLAGPOINTEREXTPROC glad_glEdgeFlagPointerEXT;
+PFNGLGETPOINTERVEXTPROC glad_glGetPointervEXT;
+PFNGLINDEXPOINTEREXTPROC glad_glIndexPointerEXT;
+PFNGLNORMALPOINTEREXTPROC glad_glNormalPointerEXT;
+PFNGLTEXCOORDPOINTEREXTPROC glad_glTexCoordPointerEXT;
+PFNGLVERTEXPOINTEREXTPROC glad_glVertexPointerEXT;
+PFNGLBEGINVERTEXSHADEREXTPROC glad_glBeginVertexShaderEXT;
+PFNGLENDVERTEXSHADEREXTPROC glad_glEndVertexShaderEXT;
+PFNGLBINDVERTEXSHADEREXTPROC glad_glBindVertexShaderEXT;
+PFNGLGENVERTEXSHADERSEXTPROC glad_glGenVertexShadersEXT;
+PFNGLDELETEVERTEXSHADEREXTPROC glad_glDeleteVertexShaderEXT;
+PFNGLSHADEROP1EXTPROC glad_glShaderOp1EXT;
+PFNGLSHADEROP2EXTPROC glad_glShaderOp2EXT;
+PFNGLSHADEROP3EXTPROC glad_glShaderOp3EXT;
+PFNGLSWIZZLEEXTPROC glad_glSwizzleEXT;
+PFNGLWRITEMASKEXTPROC glad_glWriteMaskEXT;
+PFNGLINSERTCOMPONENTEXTPROC glad_glInsertComponentEXT;
+PFNGLEXTRACTCOMPONENTEXTPROC glad_glExtractComponentEXT;
+PFNGLGENSYMBOLSEXTPROC glad_glGenSymbolsEXT;
+PFNGLSETINVARIANTEXTPROC glad_glSetInvariantEXT;
+PFNGLSETLOCALCONSTANTEXTPROC glad_glSetLocalConstantEXT;
+PFNGLVARIANTBVEXTPROC glad_glVariantbvEXT;
+PFNGLVARIANTSVEXTPROC glad_glVariantsvEXT;
+PFNGLVARIANTIVEXTPROC glad_glVariantivEXT;
+PFNGLVARIANTFVEXTPROC glad_glVariantfvEXT;
+PFNGLVARIANTDVEXTPROC glad_glVariantdvEXT;
+PFNGLVARIANTUBVEXTPROC glad_glVariantubvEXT;
+PFNGLVARIANTUSVEXTPROC glad_glVariantusvEXT;
+PFNGLVARIANTUIVEXTPROC glad_glVariantuivEXT;
+PFNGLVARIANTPOINTEREXTPROC glad_glVariantPointerEXT;
+PFNGLENABLEVARIANTCLIENTSTATEEXTPROC glad_glEnableVariantClientStateEXT;
+PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC glad_glDisableVariantClientStateEXT;
+PFNGLBINDLIGHTPARAMETEREXTPROC glad_glBindLightParameterEXT;
+PFNGLBINDMATERIALPARAMETEREXTPROC glad_glBindMaterialParameterEXT;
+PFNGLBINDTEXGENPARAMETEREXTPROC glad_glBindTexGenParameterEXT;
+PFNGLBINDTEXTUREUNITPARAMETEREXTPROC glad_glBindTextureUnitParameterEXT;
+PFNGLBINDPARAMETEREXTPROC glad_glBindParameterEXT;
+PFNGLISVARIANTENABLEDEXTPROC glad_glIsVariantEnabledEXT;
+PFNGLGETVARIANTBOOLEANVEXTPROC glad_glGetVariantBooleanvEXT;
+PFNGLGETVARIANTINTEGERVEXTPROC glad_glGetVariantIntegervEXT;
+PFNGLGETVARIANTFLOATVEXTPROC glad_glGetVariantFloatvEXT;
+PFNGLGETVARIANTPOINTERVEXTPROC glad_glGetVariantPointervEXT;
+PFNGLGETINVARIANTBOOLEANVEXTPROC glad_glGetInvariantBooleanvEXT;
+PFNGLGETINVARIANTINTEGERVEXTPROC glad_glGetInvariantIntegervEXT;
+PFNGLGETINVARIANTFLOATVEXTPROC glad_glGetInvariantFloatvEXT;
+PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC glad_glGetLocalConstantBooleanvEXT;
+PFNGLGETLOCALCONSTANTINTEGERVEXTPROC glad_glGetLocalConstantIntegervEXT;
+PFNGLGETLOCALCONSTANTFLOATVEXTPROC glad_glGetLocalConstantFloatvEXT;
+static void load_GL_VERSION_1_0(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_1_0) return;
+ glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
+ glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace");
+ glad_glHint = (PFNGLHINTPROC)load("glHint");
+ glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth");
+ glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize");
+ glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode");
+ glad_glScissor = (PFNGLSCISSORPROC)load("glScissor");
+ glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf");
+ glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv");
+ glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri");
+ glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv");
+ glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D");
+ glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D");
+ glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer");
+ glad_glClear = (PFNGLCLEARPROC)load("glClear");
+ glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor");
+ glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil");
+ glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth");
+ glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask");
+ glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask");
+ glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask");
+ glad_glDisable = (PFNGLDISABLEPROC)load("glDisable");
+ glad_glEnable = (PFNGLENABLEPROC)load("glEnable");
+ glad_glFinish = (PFNGLFINISHPROC)load("glFinish");
+ glad_glFlush = (PFNGLFLUSHPROC)load("glFlush");
+ glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc");
+ glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp");
+ glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc");
+ glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp");
+ glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc");
+ glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref");
+ glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei");
+ glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer");
+ glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels");
+ glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv");
+ glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev");
+ glad_glGetError = (PFNGLGETERRORPROC)load("glGetError");
+ glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv");
+ glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv");
+ glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString");
+ glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage");
+ glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv");
+ glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv");
+ glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv");
+ glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv");
+ glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled");
+ glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange");
+ glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport");
+}
+static void load_GL_VERSION_1_1(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_1_1) return;
+ glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays");
+ glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements");
+ glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset");
+ glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D");
+ glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D");
+ glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D");
+ glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D");
+ glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D");
+ glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D");
+ glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture");
+ glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures");
+ glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures");
+ glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture");
+}
+static void load_GL_VERSION_1_2(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_1_2) return;
+ glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements");
+ glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D");
+ glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D");
+ glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D");
+}
+static void load_GL_VERSION_1_3(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_1_3) return;
+ glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture");
+ glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage");
+ glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D");
+ glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D");
+ glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D");
+ glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D");
+ glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D");
+ glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D");
+ glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage");
+}
+static void load_GL_VERSION_1_4(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_1_4) return;
+ glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate");
+ glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays");
+ glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements");
+ glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf");
+ glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv");
+ glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri");
+ glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv");
+ glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor");
+ glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation");
+}
+static void load_GL_VERSION_1_5(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_1_5) return;
+ glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries");
+ glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries");
+ glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery");
+ glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery");
+ glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery");
+ glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv");
+ glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv");
+ glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv");
+ glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer");
+ glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers");
+ glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers");
+ glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer");
+ glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData");
+ glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData");
+ glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData");
+ glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer");
+ glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer");
+ glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv");
+ glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv");
+}
+static void load_GL_VERSION_2_0(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_2_0) return;
+ glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate");
+ glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers");
+ glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate");
+ glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate");
+ glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate");
+ glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader");
+ glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation");
+ glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader");
+ glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram");
+ glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader");
+ glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram");
+ glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader");
+ glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader");
+ glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray");
+ glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray");
+ glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib");
+ glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform");
+ glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders");
+ glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation");
+ glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv");
+ glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog");
+ glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv");
+ glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog");
+ glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource");
+ glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation");
+ glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv");
+ glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv");
+ glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv");
+ glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv");
+ glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv");
+ glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv");
+ glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram");
+ glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader");
+ glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram");
+ glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource");
+ glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram");
+ glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f");
+ glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f");
+ glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f");
+ glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f");
+ glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i");
+ glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i");
+ glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i");
+ glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i");
+ glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv");
+ glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv");
+ glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv");
+ glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv");
+ glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv");
+ glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv");
+ glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv");
+ glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv");
+ glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv");
+ glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv");
+ glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv");
+ glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram");
+ glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d");
+ glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv");
+ glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f");
+ glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv");
+ glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s");
+ glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv");
+ glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d");
+ glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv");
+ glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f");
+ glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv");
+ glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s");
+ glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv");
+ glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d");
+ glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv");
+ glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f");
+ glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv");
+ glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s");
+ glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv");
+ glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv");
+ glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv");
+ glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv");
+ glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub");
+ glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv");
+ glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv");
+ glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv");
+ glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv");
+ glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d");
+ glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv");
+ glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f");
+ glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv");
+ glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv");
+ glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s");
+ glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv");
+ glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv");
+ glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv");
+ glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv");
+ glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer");
+}
+static void load_GL_VERSION_2_1(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_2_1) return;
+ glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv");
+ glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv");
+ glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv");
+ glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv");
+ glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv");
+ glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv");
+}
+static void load_GL_VERSION_3_0(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_3_0) return;
+ glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski");
+ glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v");
+ glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v");
+ glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei");
+ glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei");
+ glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi");
+ glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback");
+ glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback");
+ glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange");
+ glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase");
+ glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings");
+ glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying");
+ glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor");
+ glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender");
+ glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender");
+ glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer");
+ glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv");
+ glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv");
+ glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i");
+ glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i");
+ glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i");
+ glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i");
+ glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui");
+ glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui");
+ glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui");
+ glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui");
+ glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv");
+ glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv");
+ glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv");
+ glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv");
+ glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv");
+ glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv");
+ glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv");
+ glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv");
+ glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv");
+ glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv");
+ glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv");
+ glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv");
+ glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv");
+ glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation");
+ glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation");
+ glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui");
+ glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui");
+ glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui");
+ glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui");
+ glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv");
+ glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv");
+ glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv");
+ glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv");
+ glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv");
+ glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv");
+ glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv");
+ glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv");
+ glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv");
+ glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv");
+ glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv");
+ glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi");
+ glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi");
+ glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer");
+ glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer");
+ glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers");
+ glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers");
+ glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage");
+ glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv");
+ glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer");
+ glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer");
+ glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers");
+ glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers");
+ glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus");
+ glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D");
+ glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D");
+ glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D");
+ glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer");
+ glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv");
+ glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap");
+ glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer");
+ glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample");
+ glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer");
+ glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange");
+ glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange");
+ glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray");
+ glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays");
+ glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays");
+ glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray");
+}
+static void load_GL_VERSION_3_1(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_3_1) return;
+ glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced");
+ glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced");
+ glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer");
+ glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex");
+ glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData");
+ glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices");
+ glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv");
+ glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName");
+ glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex");
+ glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv");
+ glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName");
+ glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding");
+ glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange");
+ glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase");
+ glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v");
+}
+static void load_GL_VERSION_3_2(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_3_2) return;
+ glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex");
+ glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex");
+ glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex");
+ glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex");
+ glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex");
+ glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync");
+ glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync");
+ glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync");
+ glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync");
+ glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync");
+ glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v");
+ glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv");
+ glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v");
+ glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v");
+ glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture");
+ glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample");
+ glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample");
+ glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv");
+ glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski");
+}
+static void load_GL_VERSION_3_3(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_3_3) return;
+ glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)load("glBindFragDataLocationIndexed");
+ glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC)load("glGetFragDataIndex");
+ glad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load("glGenSamplers");
+ glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load("glDeleteSamplers");
+ glad_glIsSampler = (PFNGLISSAMPLERPROC)load("glIsSampler");
+ glad_glBindSampler = (PFNGLBINDSAMPLERPROC)load("glBindSampler");
+ glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load("glSamplerParameteri");
+ glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load("glSamplerParameteriv");
+ glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load("glSamplerParameterf");
+ glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load("glSamplerParameterfv");
+ glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load("glSamplerParameterIiv");
+ glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load("glSamplerParameterIuiv");
+ glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load("glGetSamplerParameteriv");
+ glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load("glGetSamplerParameterIiv");
+ glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load("glGetSamplerParameterfv");
+ glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load("glGetSamplerParameterIuiv");
+ glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC)load("glQueryCounter");
+ glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)load("glGetQueryObjecti64v");
+ glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)load("glGetQueryObjectui64v");
+ glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load("glVertexAttribDivisor");
+ glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC)load("glVertexAttribP1ui");
+ glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC)load("glVertexAttribP1uiv");
+ glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC)load("glVertexAttribP2ui");
+ glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC)load("glVertexAttribP2uiv");
+ glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC)load("glVertexAttribP3ui");
+ glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC)load("glVertexAttribP3uiv");
+ glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC)load("glVertexAttribP4ui");
+ glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC)load("glVertexAttribP4uiv");
+ glad_glVertexP2ui = (PFNGLVERTEXP2UIPROC)load("glVertexP2ui");
+ glad_glVertexP2uiv = (PFNGLVERTEXP2UIVPROC)load("glVertexP2uiv");
+ glad_glVertexP3ui = (PFNGLVERTEXP3UIPROC)load("glVertexP3ui");
+ glad_glVertexP3uiv = (PFNGLVERTEXP3UIVPROC)load("glVertexP3uiv");
+ glad_glVertexP4ui = (PFNGLVERTEXP4UIPROC)load("glVertexP4ui");
+ glad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC)load("glVertexP4uiv");
+ glad_glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC)load("glTexCoordP1ui");
+ glad_glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC)load("glTexCoordP1uiv");
+ glad_glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC)load("glTexCoordP2ui");
+ glad_glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC)load("glTexCoordP2uiv");
+ glad_glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC)load("glTexCoordP3ui");
+ glad_glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC)load("glTexCoordP3uiv");
+ glad_glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC)load("glTexCoordP4ui");
+ glad_glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC)load("glTexCoordP4uiv");
+ glad_glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC)load("glMultiTexCoordP1ui");
+ glad_glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC)load("glMultiTexCoordP1uiv");
+ glad_glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC)load("glMultiTexCoordP2ui");
+ glad_glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC)load("glMultiTexCoordP2uiv");
+ glad_glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC)load("glMultiTexCoordP3ui");
+ glad_glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC)load("glMultiTexCoordP3uiv");
+ glad_glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC)load("glMultiTexCoordP4ui");
+ glad_glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC)load("glMultiTexCoordP4uiv");
+ glad_glNormalP3ui = (PFNGLNORMALP3UIPROC)load("glNormalP3ui");
+ glad_glNormalP3uiv = (PFNGLNORMALP3UIVPROC)load("glNormalP3uiv");
+ glad_glColorP3ui = (PFNGLCOLORP3UIPROC)load("glColorP3ui");
+ glad_glColorP3uiv = (PFNGLCOLORP3UIVPROC)load("glColorP3uiv");
+ glad_glColorP4ui = (PFNGLCOLORP4UIPROC)load("glColorP4ui");
+ glad_glColorP4uiv = (PFNGLCOLORP4UIVPROC)load("glColorP4uiv");
+ glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui");
+ glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv");
+}
+static void load_GL_AMD_debug_output(GLADloadproc load) {
+ if(!GLAD_GL_AMD_debug_output) return;
+ glad_glDebugMessageEnableAMD = (PFNGLDEBUGMESSAGEENABLEAMDPROC)load("glDebugMessageEnableAMD");
+ glad_glDebugMessageInsertAMD = (PFNGLDEBUGMESSAGEINSERTAMDPROC)load("glDebugMessageInsertAMD");
+ glad_glDebugMessageCallbackAMD = (PFNGLDEBUGMESSAGECALLBACKAMDPROC)load("glDebugMessageCallbackAMD");
+ glad_glGetDebugMessageLogAMD = (PFNGLGETDEBUGMESSAGELOGAMDPROC)load("glGetDebugMessageLogAMD");
+}
+static void load_GL_ARB_ES2_compatibility(GLADloadproc load) {
+ if(!GLAD_GL_ARB_ES2_compatibility) return;
+ glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)load("glReleaseShaderCompiler");
+ glad_glShaderBinary = (PFNGLSHADERBINARYPROC)load("glShaderBinary");
+ glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)load("glGetShaderPrecisionFormat");
+ glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load("glDepthRangef");
+ glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load("glClearDepthf");
+}
+static void load_GL_ARB_buffer_storage(GLADloadproc load) {
+ if(!GLAD_GL_ARB_buffer_storage) return;
+ glad_glBufferStorage = (PFNGLBUFFERSTORAGEPROC)load("glBufferStorage");
+}
+static void load_GL_ARB_debug_output(GLADloadproc load) {
+ if(!GLAD_GL_ARB_debug_output) return;
+ glad_glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC)load("glDebugMessageControlARB");
+ glad_glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC)load("glDebugMessageInsertARB");
+ glad_glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)load("glDebugMessageCallbackARB");
+ glad_glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC)load("glGetDebugMessageLogARB");
+}
+static void load_GL_ARB_draw_buffers(GLADloadproc load) {
+ if(!GLAD_GL_ARB_draw_buffers) return;
+ glad_glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC)load("glDrawBuffersARB");
+}
+static void load_GL_ARB_draw_buffers_blend(GLADloadproc load) {
+ if(!GLAD_GL_ARB_draw_buffers_blend) return;
+ glad_glBlendEquationiARB = (PFNGLBLENDEQUATIONIARBPROC)load("glBlendEquationiARB");
+ glad_glBlendEquationSeparateiARB = (PFNGLBLENDEQUATIONSEPARATEIARBPROC)load("glBlendEquationSeparateiARB");
+ glad_glBlendFunciARB = (PFNGLBLENDFUNCIARBPROC)load("glBlendFunciARB");
+ glad_glBlendFuncSeparateiARB = (PFNGLBLENDFUNCSEPARATEIARBPROC)load("glBlendFuncSeparateiARB");
+}
+static void load_GL_ARB_fragment_program(GLADloadproc load) {
+ if(!GLAD_GL_ARB_fragment_program) return;
+ glad_glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)load("glProgramStringARB");
+ glad_glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)load("glBindProgramARB");
+ glad_glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)load("glDeleteProgramsARB");
+ glad_glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)load("glGenProgramsARB");
+ glad_glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC)load("glProgramEnvParameter4dARB");
+ glad_glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC)load("glProgramEnvParameter4dvARB");
+ glad_glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC)load("glProgramEnvParameter4fARB");
+ glad_glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)load("glProgramEnvParameter4fvARB");
+ glad_glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC)load("glProgramLocalParameter4dARB");
+ glad_glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)load("glProgramLocalParameter4dvARB");
+ glad_glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC)load("glProgramLocalParameter4fARB");
+ glad_glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)load("glProgramLocalParameter4fvARB");
+ glad_glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC)load("glGetProgramEnvParameterdvARB");
+ glad_glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC)load("glGetProgramEnvParameterfvARB");
+ glad_glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)load("glGetProgramLocalParameterdvARB");
+ glad_glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)load("glGetProgramLocalParameterfvARB");
+ glad_glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC)load("glGetProgramivARB");
+ glad_glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC)load("glGetProgramStringARB");
+ glad_glIsProgramARB = (PFNGLISPROGRAMARBPROC)load("glIsProgramARB");
+}
+static void load_GL_ARB_framebuffer_object(GLADloadproc load) {
+ if(!GLAD_GL_ARB_framebuffer_object) return;
+ glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer");
+ glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer");
+ glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers");
+ glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers");
+ glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage");
+ glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv");
+ glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer");
+ glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer");
+ glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers");
+ glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers");
+ glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus");
+ glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D");
+ glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D");
+ glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D");
+ glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer");
+ glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv");
+ glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap");
+ glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer");
+ glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample");
+ glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer");
+}
+static void load_GL_ARB_multisample(GLADloadproc load) {
+ if(!GLAD_GL_ARB_multisample) return;
+ glad_glSampleCoverageARB = (PFNGLSAMPLECOVERAGEARBPROC)load("glSampleCoverageARB");
+}
+static void load_GL_ARB_sample_locations(GLADloadproc load) {
+ if(!GLAD_GL_ARB_sample_locations) return;
+ glad_glFramebufferSampleLocationsfvARB = (PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)load("glFramebufferSampleLocationsfvARB");
+ glad_glNamedFramebufferSampleLocationsfvARB = (PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)load("glNamedFramebufferSampleLocationsfvARB");
+ glad_glEvaluateDepthValuesARB = (PFNGLEVALUATEDEPTHVALUESARBPROC)load("glEvaluateDepthValuesARB");
+}
+static void load_GL_ARB_texture_compression(GLADloadproc load) {
+ if(!GLAD_GL_ARB_texture_compression) return;
+ glad_glCompressedTexImage3DARB = (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)load("glCompressedTexImage3DARB");
+ glad_glCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)load("glCompressedTexImage2DARB");
+ glad_glCompressedTexImage1DARB = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)load("glCompressedTexImage1DARB");
+ glad_glCompressedTexSubImage3DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)load("glCompressedTexSubImage3DARB");
+ glad_glCompressedTexSubImage2DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)load("glCompressedTexSubImage2DARB");
+ glad_glCompressedTexSubImage1DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)load("glCompressedTexSubImage1DARB");
+ glad_glGetCompressedTexImageARB = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)load("glGetCompressedTexImageARB");
+}
+static void load_GL_ARB_texture_multisample(GLADloadproc load) {
+ if(!GLAD_GL_ARB_texture_multisample) return;
+ glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample");
+ glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample");
+ glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv");
+ glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski");
+}
+static void load_GL_ARB_uniform_buffer_object(GLADloadproc load) {
+ if(!GLAD_GL_ARB_uniform_buffer_object) return;
+ glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices");
+ glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv");
+ glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName");
+ glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex");
+ glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv");
+ glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName");
+ glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding");
+ glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange");
+ glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase");
+ glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v");
+}
+static void load_GL_ARB_vertex_array_object(GLADloadproc load) {
+ if(!GLAD_GL_ARB_vertex_array_object) return;
+ glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray");
+ glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays");
+ glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays");
+ glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray");
+}
+static void load_GL_ARB_vertex_attrib_binding(GLADloadproc load) {
+ if(!GLAD_GL_ARB_vertex_attrib_binding) return;
+ glad_glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC)load("glBindVertexBuffer");
+ glad_glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC)load("glVertexAttribFormat");
+ glad_glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC)load("glVertexAttribIFormat");
+ glad_glVertexAttribLFormat = (PFNGLVERTEXATTRIBLFORMATPROC)load("glVertexAttribLFormat");
+ glad_glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC)load("glVertexAttribBinding");
+ glad_glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC)load("glVertexBindingDivisor");
+}
+static void load_GL_ARB_vertex_buffer_object(GLADloadproc load) {
+ if(!GLAD_GL_ARB_vertex_buffer_object) return;
+ glad_glBindBufferARB = (PFNGLBINDBUFFERARBPROC)load("glBindBufferARB");
+ glad_glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)load("glDeleteBuffersARB");
+ glad_glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)load("glGenBuffersARB");
+ glad_glIsBufferARB = (PFNGLISBUFFERARBPROC)load("glIsBufferARB");
+ glad_glBufferDataARB = (PFNGLBUFFERDATAARBPROC)load("glBufferDataARB");
+ glad_glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)load("glBufferSubDataARB");
+ glad_glGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)load("glGetBufferSubDataARB");
+ glad_glMapBufferARB = (PFNGLMAPBUFFERARBPROC)load("glMapBufferARB");
+ glad_glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)load("glUnmapBufferARB");
+ glad_glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)load("glGetBufferParameterivARB");
+ glad_glGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)load("glGetBufferPointervARB");
+}
+static void load_GL_ARB_vertex_program(GLADloadproc load) {
+ if(!GLAD_GL_ARB_vertex_program) return;
+ glad_glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC)load("glVertexAttrib1dARB");
+ glad_glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC)load("glVertexAttrib1dvARB");
+ glad_glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC)load("glVertexAttrib1fARB");
+ glad_glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC)load("glVertexAttrib1fvARB");
+ glad_glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC)load("glVertexAttrib1sARB");
+ glad_glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC)load("glVertexAttrib1svARB");
+ glad_glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC)load("glVertexAttrib2dARB");
+ glad_glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC)load("glVertexAttrib2dvARB");
+ glad_glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC)load("glVertexAttrib2fARB");
+ glad_glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC)load("glVertexAttrib2fvARB");
+ glad_glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC)load("glVertexAttrib2sARB");
+ glad_glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC)load("glVertexAttrib2svARB");
+ glad_glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC)load("glVertexAttrib3dARB");
+ glad_glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC)load("glVertexAttrib3dvARB");
+ glad_glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC)load("glVertexAttrib3fARB");
+ glad_glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC)load("glVertexAttrib3fvARB");
+ glad_glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC)load("glVertexAttrib3sARB");
+ glad_glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC)load("glVertexAttrib3svARB");
+ glad_glVertexAttrib4NbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC)load("glVertexAttrib4NbvARB");
+ glad_glVertexAttrib4NivARB = (PFNGLVERTEXATTRIB4NIVARBPROC)load("glVertexAttrib4NivARB");
+ glad_glVertexAttrib4NsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC)load("glVertexAttrib4NsvARB");
+ glad_glVertexAttrib4NubARB = (PFNGLVERTEXATTRIB4NUBARBPROC)load("glVertexAttrib4NubARB");
+ glad_glVertexAttrib4NubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC)load("glVertexAttrib4NubvARB");
+ glad_glVertexAttrib4NuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC)load("glVertexAttrib4NuivARB");
+ glad_glVertexAttrib4NusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC)load("glVertexAttrib4NusvARB");
+ glad_glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC)load("glVertexAttrib4bvARB");
+ glad_glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC)load("glVertexAttrib4dARB");
+ glad_glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC)load("glVertexAttrib4dvARB");
+ glad_glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC)load("glVertexAttrib4fARB");
+ glad_glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC)load("glVertexAttrib4fvARB");
+ glad_glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC)load("glVertexAttrib4ivARB");
+ glad_glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC)load("glVertexAttrib4sARB");
+ glad_glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC)load("glVertexAttrib4svARB");
+ glad_glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC)load("glVertexAttrib4ubvARB");
+ glad_glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC)load("glVertexAttrib4uivARB");
+ glad_glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC)load("glVertexAttrib4usvARB");
+ glad_glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)load("glVertexAttribPointerARB");
+ glad_glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)load("glEnableVertexAttribArrayARB");
+ glad_glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)load("glDisableVertexAttribArrayARB");
+ glad_glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)load("glProgramStringARB");
+ glad_glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)load("glBindProgramARB");
+ glad_glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)load("glDeleteProgramsARB");
+ glad_glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)load("glGenProgramsARB");
+ glad_glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC)load("glProgramEnvParameter4dARB");
+ glad_glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC)load("glProgramEnvParameter4dvARB");
+ glad_glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC)load("glProgramEnvParameter4fARB");
+ glad_glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)load("glProgramEnvParameter4fvARB");
+ glad_glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC)load("glProgramLocalParameter4dARB");
+ glad_glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)load("glProgramLocalParameter4dvARB");
+ glad_glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC)load("glProgramLocalParameter4fARB");
+ glad_glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)load("glProgramLocalParameter4fvARB");
+ glad_glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC)load("glGetProgramEnvParameterdvARB");
+ glad_glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC)load("glGetProgramEnvParameterfvARB");
+ glad_glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)load("glGetProgramLocalParameterdvARB");
+ glad_glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)load("glGetProgramLocalParameterfvARB");
+ glad_glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC)load("glGetProgramivARB");
+ glad_glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC)load("glGetProgramStringARB");
+ glad_glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC)load("glGetVertexAttribdvARB");
+ glad_glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC)load("glGetVertexAttribfvARB");
+ glad_glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC)load("glGetVertexAttribivARB");
+ glad_glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC)load("glGetVertexAttribPointervARB");
+ glad_glIsProgramARB = (PFNGLISPROGRAMARBPROC)load("glIsProgramARB");
+}
+static void load_GL_ARB_vertex_shader(GLADloadproc load) {
+ if(!GLAD_GL_ARB_vertex_shader) return;
+ glad_glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC)load("glVertexAttrib1fARB");
+ glad_glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC)load("glVertexAttrib1sARB");
+ glad_glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC)load("glVertexAttrib1dARB");
+ glad_glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC)load("glVertexAttrib2fARB");
+ glad_glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC)load("glVertexAttrib2sARB");
+ glad_glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC)load("glVertexAttrib2dARB");
+ glad_glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC)load("glVertexAttrib3fARB");
+ glad_glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC)load("glVertexAttrib3sARB");
+ glad_glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC)load("glVertexAttrib3dARB");
+ glad_glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC)load("glVertexAttrib4fARB");
+ glad_glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC)load("glVertexAttrib4sARB");
+ glad_glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC)load("glVertexAttrib4dARB");
+ glad_glVertexAttrib4NubARB = (PFNGLVERTEXATTRIB4NUBARBPROC)load("glVertexAttrib4NubARB");
+ glad_glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC)load("glVertexAttrib1fvARB");
+ glad_glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC)load("glVertexAttrib1svARB");
+ glad_glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC)load("glVertexAttrib1dvARB");
+ glad_glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC)load("glVertexAttrib2fvARB");
+ glad_glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC)load("glVertexAttrib2svARB");
+ glad_glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC)load("glVertexAttrib2dvARB");
+ glad_glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC)load("glVertexAttrib3fvARB");
+ glad_glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC)load("glVertexAttrib3svARB");
+ glad_glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC)load("glVertexAttrib3dvARB");
+ glad_glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC)load("glVertexAttrib4fvARB");
+ glad_glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC)load("glVertexAttrib4svARB");
+ glad_glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC)load("glVertexAttrib4dvARB");
+ glad_glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC)load("glVertexAttrib4ivARB");
+ glad_glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC)load("glVertexAttrib4bvARB");
+ glad_glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC)load("glVertexAttrib4ubvARB");
+ glad_glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC)load("glVertexAttrib4usvARB");
+ glad_glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC)load("glVertexAttrib4uivARB");
+ glad_glVertexAttrib4NbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC)load("glVertexAttrib4NbvARB");
+ glad_glVertexAttrib4NsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC)load("glVertexAttrib4NsvARB");
+ glad_glVertexAttrib4NivARB = (PFNGLVERTEXATTRIB4NIVARBPROC)load("glVertexAttrib4NivARB");
+ glad_glVertexAttrib4NubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC)load("glVertexAttrib4NubvARB");
+ glad_glVertexAttrib4NusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC)load("glVertexAttrib4NusvARB");
+ glad_glVertexAttrib4NuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC)load("glVertexAttrib4NuivARB");
+ glad_glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)load("glVertexAttribPointerARB");
+ glad_glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)load("glEnableVertexAttribArrayARB");
+ glad_glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)load("glDisableVertexAttribArrayARB");
+ glad_glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC)load("glBindAttribLocationARB");
+ glad_glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC)load("glGetActiveAttribARB");
+ glad_glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC)load("glGetAttribLocationARB");
+ glad_glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC)load("glGetVertexAttribdvARB");
+ glad_glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC)load("glGetVertexAttribfvARB");
+ glad_glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC)load("glGetVertexAttribivARB");
+ glad_glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC)load("glGetVertexAttribPointervARB");
+}
+static void load_GL_ATI_element_array(GLADloadproc load) {
+ if(!GLAD_GL_ATI_element_array) return;
+ glad_glElementPointerATI = (PFNGLELEMENTPOINTERATIPROC)load("glElementPointerATI");
+ glad_glDrawElementArrayATI = (PFNGLDRAWELEMENTARRAYATIPROC)load("glDrawElementArrayATI");
+ glad_glDrawRangeElementArrayATI = (PFNGLDRAWRANGEELEMENTARRAYATIPROC)load("glDrawRangeElementArrayATI");
+}
+static void load_GL_ATI_fragment_shader(GLADloadproc load) {
+ if(!GLAD_GL_ATI_fragment_shader) return;
+ glad_glGenFragmentShadersATI = (PFNGLGENFRAGMENTSHADERSATIPROC)load("glGenFragmentShadersATI");
+ glad_glBindFragmentShaderATI = (PFNGLBINDFRAGMENTSHADERATIPROC)load("glBindFragmentShaderATI");
+ glad_glDeleteFragmentShaderATI = (PFNGLDELETEFRAGMENTSHADERATIPROC)load("glDeleteFragmentShaderATI");
+ glad_glBeginFragmentShaderATI = (PFNGLBEGINFRAGMENTSHADERATIPROC)load("glBeginFragmentShaderATI");
+ glad_glEndFragmentShaderATI = (PFNGLENDFRAGMENTSHADERATIPROC)load("glEndFragmentShaderATI");
+ glad_glPassTexCoordATI = (PFNGLPASSTEXCOORDATIPROC)load("glPassTexCoordATI");
+ glad_glSampleMapATI = (PFNGLSAMPLEMAPATIPROC)load("glSampleMapATI");
+ glad_glColorFragmentOp1ATI = (PFNGLCOLORFRAGMENTOP1ATIPROC)load("glColorFragmentOp1ATI");
+ glad_glColorFragmentOp2ATI = (PFNGLCOLORFRAGMENTOP2ATIPROC)load("glColorFragmentOp2ATI");
+ glad_glColorFragmentOp3ATI = (PFNGLCOLORFRAGMENTOP3ATIPROC)load("glColorFragmentOp3ATI");
+ glad_glAlphaFragmentOp1ATI = (PFNGLALPHAFRAGMENTOP1ATIPROC)load("glAlphaFragmentOp1ATI");
+ glad_glAlphaFragmentOp2ATI = (PFNGLALPHAFRAGMENTOP2ATIPROC)load("glAlphaFragmentOp2ATI");
+ glad_glAlphaFragmentOp3ATI = (PFNGLALPHAFRAGMENTOP3ATIPROC)load("glAlphaFragmentOp3ATI");
+ glad_glSetFragmentShaderConstantATI = (PFNGLSETFRAGMENTSHADERCONSTANTATIPROC)load("glSetFragmentShaderConstantATI");
+}
+static void load_GL_ATI_vertex_array_object(GLADloadproc load) {
+ if(!GLAD_GL_ATI_vertex_array_object) return;
+ glad_glNewObjectBufferATI = (PFNGLNEWOBJECTBUFFERATIPROC)load("glNewObjectBufferATI");
+ glad_glIsObjectBufferATI = (PFNGLISOBJECTBUFFERATIPROC)load("glIsObjectBufferATI");
+ glad_glUpdateObjectBufferATI = (PFNGLUPDATEOBJECTBUFFERATIPROC)load("glUpdateObjectBufferATI");
+ glad_glGetObjectBufferfvATI = (PFNGLGETOBJECTBUFFERFVATIPROC)load("glGetObjectBufferfvATI");
+ glad_glGetObjectBufferivATI = (PFNGLGETOBJECTBUFFERIVATIPROC)load("glGetObjectBufferivATI");
+ glad_glFreeObjectBufferATI = (PFNGLFREEOBJECTBUFFERATIPROC)load("glFreeObjectBufferATI");
+ glad_glArrayObjectATI = (PFNGLARRAYOBJECTATIPROC)load("glArrayObjectATI");
+ glad_glGetArrayObjectfvATI = (PFNGLGETARRAYOBJECTFVATIPROC)load("glGetArrayObjectfvATI");
+ glad_glGetArrayObjectivATI = (PFNGLGETARRAYOBJECTIVATIPROC)load("glGetArrayObjectivATI");
+ glad_glVariantArrayObjectATI = (PFNGLVARIANTARRAYOBJECTATIPROC)load("glVariantArrayObjectATI");
+ glad_glGetVariantArrayObjectfvATI = (PFNGLGETVARIANTARRAYOBJECTFVATIPROC)load("glGetVariantArrayObjectfvATI");
+ glad_glGetVariantArrayObjectivATI = (PFNGLGETVARIANTARRAYOBJECTIVATIPROC)load("glGetVariantArrayObjectivATI");
+}
+static void load_GL_EXT_blend_color(GLADloadproc load) {
+ if(!GLAD_GL_EXT_blend_color) return;
+ glad_glBlendColorEXT = (PFNGLBLENDCOLOREXTPROC)load("glBlendColorEXT");
+}
+static void load_GL_EXT_blend_equation_separate(GLADloadproc load) {
+ if(!GLAD_GL_EXT_blend_equation_separate) return;
+ glad_glBlendEquationSeparateEXT = (PFNGLBLENDEQUATIONSEPARATEEXTPROC)load("glBlendEquationSeparateEXT");
+}
+static void load_GL_EXT_blend_func_separate(GLADloadproc load) {
+ if(!GLAD_GL_EXT_blend_func_separate) return;
+ glad_glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC)load("glBlendFuncSeparateEXT");
+}
+static void load_GL_EXT_framebuffer_blit(GLADloadproc load) {
+ if(!GLAD_GL_EXT_framebuffer_blit) return;
+ glad_glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC)load("glBlitFramebufferEXT");
+}
+static void load_GL_EXT_framebuffer_multisample(GLADloadproc load) {
+ if(!GLAD_GL_EXT_framebuffer_multisample) return;
+ glad_glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)load("glRenderbufferStorageMultisampleEXT");
+}
+static void load_GL_EXT_framebuffer_object(GLADloadproc load) {
+ if(!GLAD_GL_EXT_framebuffer_object) return;
+ glad_glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)load("glIsRenderbufferEXT");
+ glad_glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)load("glBindRenderbufferEXT");
+ glad_glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)load("glDeleteRenderbuffersEXT");
+ glad_glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)load("glGenRenderbuffersEXT");
+ glad_glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)load("glRenderbufferStorageEXT");
+ glad_glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)load("glGetRenderbufferParameterivEXT");
+ glad_glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC)load("glIsFramebufferEXT");
+ glad_glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)load("glBindFramebufferEXT");
+ glad_glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)load("glDeleteFramebuffersEXT");
+ glad_glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)load("glGenFramebuffersEXT");
+ glad_glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)load("glCheckFramebufferStatusEXT");
+ glad_glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)load("glFramebufferTexture1DEXT");
+ glad_glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)load("glFramebufferTexture2DEXT");
+ glad_glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)load("glFramebufferTexture3DEXT");
+ glad_glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)load("glFramebufferRenderbufferEXT");
+ glad_glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)load("glGetFramebufferAttachmentParameterivEXT");
+ glad_glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)load("glGenerateMipmapEXT");
+}
+static void load_GL_EXT_vertex_array(GLADloadproc load) {
+ if(!GLAD_GL_EXT_vertex_array) return;
+ glad_glArrayElementEXT = (PFNGLARRAYELEMENTEXTPROC)load("glArrayElementEXT");
+ glad_glColorPointerEXT = (PFNGLCOLORPOINTEREXTPROC)load("glColorPointerEXT");
+ glad_glDrawArraysEXT = (PFNGLDRAWARRAYSEXTPROC)load("glDrawArraysEXT");
+ glad_glEdgeFlagPointerEXT = (PFNGLEDGEFLAGPOINTEREXTPROC)load("glEdgeFlagPointerEXT");
+ glad_glGetPointervEXT = (PFNGLGETPOINTERVEXTPROC)load("glGetPointervEXT");
+ glad_glIndexPointerEXT = (PFNGLINDEXPOINTEREXTPROC)load("glIndexPointerEXT");
+ glad_glNormalPointerEXT = (PFNGLNORMALPOINTEREXTPROC)load("glNormalPointerEXT");
+ glad_glTexCoordPointerEXT = (PFNGLTEXCOORDPOINTEREXTPROC)load("glTexCoordPointerEXT");
+ glad_glVertexPointerEXT = (PFNGLVERTEXPOINTEREXTPROC)load("glVertexPointerEXT");
+}
+static void load_GL_EXT_vertex_shader(GLADloadproc load) {
+ if(!GLAD_GL_EXT_vertex_shader) return;
+ glad_glBeginVertexShaderEXT = (PFNGLBEGINVERTEXSHADEREXTPROC)load("glBeginVertexShaderEXT");
+ glad_glEndVertexShaderEXT = (PFNGLENDVERTEXSHADEREXTPROC)load("glEndVertexShaderEXT");
+ glad_glBindVertexShaderEXT = (PFNGLBINDVERTEXSHADEREXTPROC)load("glBindVertexShaderEXT");
+ glad_glGenVertexShadersEXT = (PFNGLGENVERTEXSHADERSEXTPROC)load("glGenVertexShadersEXT");
+ glad_glDeleteVertexShaderEXT = (PFNGLDELETEVERTEXSHADEREXTPROC)load("glDeleteVertexShaderEXT");
+ glad_glShaderOp1EXT = (PFNGLSHADEROP1EXTPROC)load("glShaderOp1EXT");
+ glad_glShaderOp2EXT = (PFNGLSHADEROP2EXTPROC)load("glShaderOp2EXT");
+ glad_glShaderOp3EXT = (PFNGLSHADEROP3EXTPROC)load("glShaderOp3EXT");
+ glad_glSwizzleEXT = (PFNGLSWIZZLEEXTPROC)load("glSwizzleEXT");
+ glad_glWriteMaskEXT = (PFNGLWRITEMASKEXTPROC)load("glWriteMaskEXT");
+ glad_glInsertComponentEXT = (PFNGLINSERTCOMPONENTEXTPROC)load("glInsertComponentEXT");
+ glad_glExtractComponentEXT = (PFNGLEXTRACTCOMPONENTEXTPROC)load("glExtractComponentEXT");
+ glad_glGenSymbolsEXT = (PFNGLGENSYMBOLSEXTPROC)load("glGenSymbolsEXT");
+ glad_glSetInvariantEXT = (PFNGLSETINVARIANTEXTPROC)load("glSetInvariantEXT");
+ glad_glSetLocalConstantEXT = (PFNGLSETLOCALCONSTANTEXTPROC)load("glSetLocalConstantEXT");
+ glad_glVariantbvEXT = (PFNGLVARIANTBVEXTPROC)load("glVariantbvEXT");
+ glad_glVariantsvEXT = (PFNGLVARIANTSVEXTPROC)load("glVariantsvEXT");
+ glad_glVariantivEXT = (PFNGLVARIANTIVEXTPROC)load("glVariantivEXT");
+ glad_glVariantfvEXT = (PFNGLVARIANTFVEXTPROC)load("glVariantfvEXT");
+ glad_glVariantdvEXT = (PFNGLVARIANTDVEXTPROC)load("glVariantdvEXT");
+ glad_glVariantubvEXT = (PFNGLVARIANTUBVEXTPROC)load("glVariantubvEXT");
+ glad_glVariantusvEXT = (PFNGLVARIANTUSVEXTPROC)load("glVariantusvEXT");
+ glad_glVariantuivEXT = (PFNGLVARIANTUIVEXTPROC)load("glVariantuivEXT");
+ glad_glVariantPointerEXT = (PFNGLVARIANTPOINTEREXTPROC)load("glVariantPointerEXT");
+ glad_glEnableVariantClientStateEXT = (PFNGLENABLEVARIANTCLIENTSTATEEXTPROC)load("glEnableVariantClientStateEXT");
+ glad_glDisableVariantClientStateEXT = (PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC)load("glDisableVariantClientStateEXT");
+ glad_glBindLightParameterEXT = (PFNGLBINDLIGHTPARAMETEREXTPROC)load("glBindLightParameterEXT");
+ glad_glBindMaterialParameterEXT = (PFNGLBINDMATERIALPARAMETEREXTPROC)load("glBindMaterialParameterEXT");
+ glad_glBindTexGenParameterEXT = (PFNGLBINDTEXGENPARAMETEREXTPROC)load("glBindTexGenParameterEXT");
+ glad_glBindTextureUnitParameterEXT = (PFNGLBINDTEXTUREUNITPARAMETEREXTPROC)load("glBindTextureUnitParameterEXT");
+ glad_glBindParameterEXT = (PFNGLBINDPARAMETEREXTPROC)load("glBindParameterEXT");
+ glad_glIsVariantEnabledEXT = (PFNGLISVARIANTENABLEDEXTPROC)load("glIsVariantEnabledEXT");
+ glad_glGetVariantBooleanvEXT = (PFNGLGETVARIANTBOOLEANVEXTPROC)load("glGetVariantBooleanvEXT");
+ glad_glGetVariantIntegervEXT = (PFNGLGETVARIANTINTEGERVEXTPROC)load("glGetVariantIntegervEXT");
+ glad_glGetVariantFloatvEXT = (PFNGLGETVARIANTFLOATVEXTPROC)load("glGetVariantFloatvEXT");
+ glad_glGetVariantPointervEXT = (PFNGLGETVARIANTPOINTERVEXTPROC)load("glGetVariantPointervEXT");
+ glad_glGetInvariantBooleanvEXT = (PFNGLGETINVARIANTBOOLEANVEXTPROC)load("glGetInvariantBooleanvEXT");
+ glad_glGetInvariantIntegervEXT = (PFNGLGETINVARIANTINTEGERVEXTPROC)load("glGetInvariantIntegervEXT");
+ glad_glGetInvariantFloatvEXT = (PFNGLGETINVARIANTFLOATVEXTPROC)load("glGetInvariantFloatvEXT");
+ glad_glGetLocalConstantBooleanvEXT = (PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC)load("glGetLocalConstantBooleanvEXT");
+ glad_glGetLocalConstantIntegervEXT = (PFNGLGETLOCALCONSTANTINTEGERVEXTPROC)load("glGetLocalConstantIntegervEXT");
+ glad_glGetLocalConstantFloatvEXT = (PFNGLGETLOCALCONSTANTFLOATVEXTPROC)load("glGetLocalConstantFloatvEXT");
+}
+static int find_extensionsGL(void) {
+ if (!get_exts()) return 0;
+ GLAD_GL_AMD_debug_output = has_ext("GL_AMD_debug_output");
+ GLAD_GL_AMD_query_buffer_object = has_ext("GL_AMD_query_buffer_object");
+ GLAD_GL_ARB_ES2_compatibility = has_ext("GL_ARB_ES2_compatibility");
+ GLAD_GL_ARB_ES3_compatibility = has_ext("GL_ARB_ES3_compatibility");
+ GLAD_GL_ARB_buffer_storage = has_ext("GL_ARB_buffer_storage");
+ GLAD_GL_ARB_compatibility = has_ext("GL_ARB_compatibility");
+ GLAD_GL_ARB_compressed_texture_pixel_storage = has_ext("GL_ARB_compressed_texture_pixel_storage");
+ GLAD_GL_ARB_debug_output = has_ext("GL_ARB_debug_output");
+ GLAD_GL_ARB_depth_buffer_float = has_ext("GL_ARB_depth_buffer_float");
+ GLAD_GL_ARB_depth_clamp = has_ext("GL_ARB_depth_clamp");
+ GLAD_GL_ARB_depth_texture = has_ext("GL_ARB_depth_texture");
+ GLAD_GL_ARB_draw_buffers = has_ext("GL_ARB_draw_buffers");
+ GLAD_GL_ARB_draw_buffers_blend = has_ext("GL_ARB_draw_buffers_blend");
+ GLAD_GL_ARB_explicit_attrib_location = has_ext("GL_ARB_explicit_attrib_location");
+ GLAD_GL_ARB_explicit_uniform_location = has_ext("GL_ARB_explicit_uniform_location");
+ GLAD_GL_ARB_fragment_program = has_ext("GL_ARB_fragment_program");
+ GLAD_GL_ARB_fragment_shader = has_ext("GL_ARB_fragment_shader");
+ GLAD_GL_ARB_framebuffer_object = has_ext("GL_ARB_framebuffer_object");
+ GLAD_GL_ARB_framebuffer_sRGB = has_ext("GL_ARB_framebuffer_sRGB");
+ GLAD_GL_ARB_multisample = has_ext("GL_ARB_multisample");
+ GLAD_GL_ARB_sample_locations = has_ext("GL_ARB_sample_locations");
+ GLAD_GL_ARB_texture_compression = has_ext("GL_ARB_texture_compression");
+ GLAD_GL_ARB_texture_float = has_ext("GL_ARB_texture_float");
+ GLAD_GL_ARB_texture_multisample = has_ext("GL_ARB_texture_multisample");
+ GLAD_GL_ARB_texture_non_power_of_two = has_ext("GL_ARB_texture_non_power_of_two");
+ GLAD_GL_ARB_texture_rg = has_ext("GL_ARB_texture_rg");
+ GLAD_GL_ARB_texture_swizzle = has_ext("GL_ARB_texture_swizzle");
+ GLAD_GL_ARB_uniform_buffer_object = has_ext("GL_ARB_uniform_buffer_object");
+ GLAD_GL_ARB_vertex_array_object = has_ext("GL_ARB_vertex_array_object");
+ GLAD_GL_ARB_vertex_attrib_binding = has_ext("GL_ARB_vertex_attrib_binding");
+ GLAD_GL_ARB_vertex_buffer_object = has_ext("GL_ARB_vertex_buffer_object");
+ GLAD_GL_ARB_vertex_program = has_ext("GL_ARB_vertex_program");
+ GLAD_GL_ARB_vertex_shader = has_ext("GL_ARB_vertex_shader");
+ GLAD_GL_ATI_element_array = has_ext("GL_ATI_element_array");
+ GLAD_GL_ATI_fragment_shader = has_ext("GL_ATI_fragment_shader");
+ GLAD_GL_ATI_vertex_array_object = has_ext("GL_ATI_vertex_array_object");
+ GLAD_GL_EXT_blend_color = has_ext("GL_EXT_blend_color");
+ GLAD_GL_EXT_blend_equation_separate = has_ext("GL_EXT_blend_equation_separate");
+ GLAD_GL_EXT_blend_func_separate = has_ext("GL_EXT_blend_func_separate");
+ GLAD_GL_EXT_framebuffer_blit = has_ext("GL_EXT_framebuffer_blit");
+ GLAD_GL_EXT_framebuffer_multisample = has_ext("GL_EXT_framebuffer_multisample");
+ GLAD_GL_EXT_framebuffer_multisample_blit_scaled = has_ext("GL_EXT_framebuffer_multisample_blit_scaled");
+ GLAD_GL_EXT_framebuffer_object = has_ext("GL_EXT_framebuffer_object");
+ GLAD_GL_EXT_framebuffer_sRGB = has_ext("GL_EXT_framebuffer_sRGB");
+ GLAD_GL_EXT_index_array_formats = has_ext("GL_EXT_index_array_formats");
+ GLAD_GL_EXT_texture = has_ext("GL_EXT_texture");
+ GLAD_GL_EXT_texture_compression_s3tc = has_ext("GL_EXT_texture_compression_s3tc");
+ GLAD_GL_EXT_texture_sRGB = has_ext("GL_EXT_texture_sRGB");
+ GLAD_GL_EXT_texture_swizzle = has_ext("GL_EXT_texture_swizzle");
+ GLAD_GL_EXT_vertex_array = has_ext("GL_EXT_vertex_array");
+ GLAD_GL_EXT_vertex_shader = has_ext("GL_EXT_vertex_shader");
+ free_exts();
+ return 1;
+}
+
+static void find_coreGL(void) {
+
+ /* Thank you @elmindreda
+ * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176
+ * https://github.com/glfw/glfw/blob/master/src/context.c#L36
+ */
+ int i, major, minor;
+
+ const char* version;
+ const char* prefixes[] = {
+ "OpenGL ES-CM ",
+ "OpenGL ES-CL ",
+ "OpenGL ES ",
+ NULL
+ };
+
+ version = (const char*) glGetString(GL_VERSION);
+ if (!version) return;
+
+ for (i = 0; prefixes[i]; i++) {
+ const size_t length = strlen(prefixes[i]);
+ if (strncmp(version, prefixes[i], length) == 0) {
+ version += length;
+ break;
+ }
+ }
+
+/* PR #18 */
+#ifdef _MSC_VER
+ sscanf_s(version, "%d.%d", &major, &minor);
+#else
+ sscanf(version, "%d.%d", &major, &minor);
+#endif
+
+ GLVersion.major = major; GLVersion.minor = minor;
+ max_loaded_major = major; max_loaded_minor = minor;
+ GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
+ GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;
+ GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;
+ GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;
+ GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;
+ GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1;
+ GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2;
+ GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2;
+ GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3;
+ GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3;
+ GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3;
+ GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3;
+ if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 3)) {
+ max_loaded_major = 3;
+ max_loaded_minor = 3;
+ }
+}
+
+int gladLoadGLLoader(GLADloadproc load) {
+ GLVersion.major = 0; GLVersion.minor = 0;
+ glGetString = (PFNGLGETSTRINGPROC)load("glGetString");
+ if(glGetString == NULL) return 0;
+ if(glGetString(GL_VERSION) == NULL) return 0;
+ find_coreGL();
+ load_GL_VERSION_1_0(load);
+ load_GL_VERSION_1_1(load);
+ load_GL_VERSION_1_2(load);
+ load_GL_VERSION_1_3(load);
+ load_GL_VERSION_1_4(load);
+ load_GL_VERSION_1_5(load);
+ load_GL_VERSION_2_0(load);
+ load_GL_VERSION_2_1(load);
+ load_GL_VERSION_3_0(load);
+ load_GL_VERSION_3_1(load);
+ load_GL_VERSION_3_2(load);
+ load_GL_VERSION_3_3(load);
+
+ if (!find_extensionsGL()) return 0;
+ load_GL_AMD_debug_output(load);
+ load_GL_ARB_ES2_compatibility(load);
+ load_GL_ARB_buffer_storage(load);
+ load_GL_ARB_debug_output(load);
+ load_GL_ARB_draw_buffers(load);
+ load_GL_ARB_draw_buffers_blend(load);
+ load_GL_ARB_fragment_program(load);
+ load_GL_ARB_framebuffer_object(load);
+ load_GL_ARB_multisample(load);
+ load_GL_ARB_sample_locations(load);
+ load_GL_ARB_texture_compression(load);
+ load_GL_ARB_texture_multisample(load);
+ load_GL_ARB_uniform_buffer_object(load);
+ load_GL_ARB_vertex_array_object(load);
+ load_GL_ARB_vertex_attrib_binding(load);
+ load_GL_ARB_vertex_buffer_object(load);
+ load_GL_ARB_vertex_program(load);
+ load_GL_ARB_vertex_shader(load);
+ load_GL_ATI_element_array(load);
+ load_GL_ATI_fragment_shader(load);
+ load_GL_ATI_vertex_array_object(load);
+ load_GL_EXT_blend_color(load);
+ load_GL_EXT_blend_equation_separate(load);
+ load_GL_EXT_blend_func_separate(load);
+ load_GL_EXT_framebuffer_blit(load);
+ load_GL_EXT_framebuffer_multisample(load);
+ load_GL_EXT_framebuffer_object(load);
+ load_GL_EXT_vertex_array(load);
+ load_GL_EXT_vertex_shader(load);
+ return GLVersion.major != 0 || GLVersion.minor != 0;
+}
+
+#endif // GLAD_IMPLEMENTATION
diff --git a/src/external/glfw3/COPYING.txt b/src/external/glfw3/COPYING.txt
new file mode 100644
index 00000000..ad16462a
--- /dev/null
+++ b/src/external/glfw3/COPYING.txt
@@ -0,0 +1,22 @@
+Copyright (c) 2002-2006 Marcus Geelnard
+Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would
+ be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+ distribution.
+
diff --git a/src/external/glfw3/include/GLFW/glfw3.h b/src/external/glfw3/include/GLFW/glfw3.h
new file mode 100644
index 00000000..5a0c4508
--- /dev/null
+++ b/src/external/glfw3/include/GLFW/glfw3.h
@@ -0,0 +1,4235 @@
+/*************************************************************************
+ * GLFW 3.2 - www.glfw.org
+ * A library for OpenGL, window and input
+ *------------------------------------------------------------------------
+ * Copyright (c) 2002-2006 Marcus Geelnard
+ * Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would
+ * be appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ *
+ *************************************************************************/
+
+#ifndef _glfw3_h_
+#define _glfw3_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*************************************************************************
+ * Doxygen documentation
+ *************************************************************************/
+
+/*! @file glfw3.h
+ * @brief The header of the GLFW 3 API.
+ *
+ * This is the header file of the GLFW 3 API. It defines all its types and
+ * declares all its functions.
+ *
+ * For more information about how to use this file, see @ref build_include.
+ */
+/*! @defgroup context Context reference
+ *
+ * This is the reference documentation for OpenGL and OpenGL ES context related
+ * functions. For more task-oriented information, see the @ref context_guide.
+ */
+/*! @defgroup vulkan Vulkan reference
+ *
+ * This is the reference documentation for Vulkan related functions and types.
+ * For more task-oriented information, see the @ref vulkan_guide.
+ */
+/*! @defgroup init Initialization, version and error reference
+ *
+ * This is the reference documentation for initialization and termination of
+ * the library, version management and error handling. For more task-oriented
+ * information, see the @ref intro_guide.
+ */
+/*! @defgroup input Input reference
+ *
+ * This is the reference documentation for input related functions and types.
+ * For more task-oriented information, see the @ref input_guide.
+ */
+/*! @defgroup monitor Monitor reference
+ *
+ * This is the reference documentation for monitor related functions and types.
+ * For more task-oriented information, see the @ref monitor_guide.
+ */
+/*! @defgroup window Window reference
+ *
+ * This is the reference documentation for window related functions and types,
+ * including creation, deletion and event polling. For more task-oriented
+ * information, see the @ref window_guide.
+ */
+
+
+/*************************************************************************
+ * Compiler- and platform-specific preprocessor work
+ *************************************************************************/
+
+/* If we are we on Windows, we want a single define for it.
+ */
+#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__))
+ #define _WIN32
+#endif /* _WIN32 */
+
+/* It is customary to use APIENTRY for OpenGL function pointer declarations on
+ * all platforms. Additionally, the Windows OpenGL header needs APIENTRY.
+ */
+#ifndef APIENTRY
+ #ifdef _WIN32
+ #define APIENTRY __stdcall
+ #else
+ #define APIENTRY
+ #endif
+#endif /* APIENTRY */
+
+/* Some Windows OpenGL headers need this.
+ */
+#if !defined(WINGDIAPI) && defined(_WIN32)
+ #define WINGDIAPI __declspec(dllimport)
+ #define GLFW_WINGDIAPI_DEFINED
+#endif /* WINGDIAPI */
+
+/* Some Windows GLU headers need this.
+ */
+#if !defined(CALLBACK) && defined(_WIN32)
+ #define CALLBACK __stdcall
+ #define GLFW_CALLBACK_DEFINED
+#endif /* CALLBACK */
+
+/* Most Windows GLU headers need wchar_t.
+ * The OS X OpenGL header blocks the definition of ptrdiff_t by glext.h.
+ * Include it unconditionally to avoid surprising side-effects.
+ */
+#include <stddef.h>
+#include <stdint.h>
+
+/* Include the chosen client API headers.
+ */
+#if defined(__APPLE__)
+ #if defined(GLFW_INCLUDE_GLCOREARB)
+ #include <OpenGL/gl3.h>
+ #if defined(GLFW_INCLUDE_GLEXT)
+ #include <OpenGL/gl3ext.h>
+ #endif
+ #elif !defined(GLFW_INCLUDE_NONE)
+ #if !defined(GLFW_INCLUDE_GLEXT)
+ #define GL_GLEXT_LEGACY
+ #endif
+ #include <OpenGL/gl.h>
+ #endif
+ #if defined(GLFW_INCLUDE_GLU)
+ #include <OpenGL/glu.h>
+ #endif
+#else
+ #if defined(GLFW_INCLUDE_GLCOREARB)
+ #include <GL/glcorearb.h>
+ #elif defined(GLFW_INCLUDE_ES1)
+ #include <GLES/gl.h>
+ #if defined(GLFW_INCLUDE_GLEXT)
+ #include <GLES/glext.h>
+ #endif
+ #elif defined(GLFW_INCLUDE_ES2)
+ #include <GLES2/gl2.h>
+ #if defined(GLFW_INCLUDE_GLEXT)
+ #include <GLES2/gl2ext.h>
+ #endif
+ #elif defined(GLFW_INCLUDE_ES3)
+ #include <GLES3/gl3.h>
+ #if defined(GLFW_INCLUDE_GLEXT)
+ #include <GLES2/gl2ext.h>
+ #endif
+ #elif defined(GLFW_INCLUDE_ES31)
+ #include <GLES3/gl31.h>
+ #if defined(GLFW_INCLUDE_GLEXT)
+ #include <GLES2/gl2ext.h>
+ #endif
+ #elif defined(GLFW_INCLUDE_VULKAN)
+ #include <vulkan/vulkan.h>
+ #elif !defined(GLFW_INCLUDE_NONE)
+ #include <GL/gl.h>
+ #if defined(GLFW_INCLUDE_GLEXT)
+ #include <GL/glext.h>
+ #endif
+ #endif
+ #if defined(GLFW_INCLUDE_GLU)
+ #include <GL/glu.h>
+ #endif
+#endif
+
+#if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL)
+ /* GLFW_DLL must be defined by applications that are linking against the DLL
+ * version of the GLFW library. _GLFW_BUILD_DLL is defined by the GLFW
+ * configuration header when compiling the DLL version of the library.
+ */
+ #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined"
+#endif
+
+/* GLFWAPI is used to declare public API functions for export
+ * from the DLL / shared library / dynamic library.
+ */
+#if defined(_WIN32) && defined(_GLFW_BUILD_DLL)
+ /* We are building GLFW as a Win32 DLL */
+ #define GLFWAPI __declspec(dllexport)
+#elif defined(_WIN32) && defined(GLFW_DLL)
+ /* We are calling GLFW as a Win32 DLL */
+ #define GLFWAPI __declspec(dllimport)
+#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL)
+ /* We are building GLFW as a shared / dynamic library */
+ #define GLFWAPI __attribute__((visibility("default")))
+#else
+ /* We are building or calling GLFW as a static library */
+ #define GLFWAPI
+#endif
+
+
+/*************************************************************************
+ * GLFW API tokens
+ *************************************************************************/
+
+/*! @name GLFW version macros
+ * @{ */
+/*! @brief The major version number of the GLFW library.
+ *
+ * This is incremented when the API is changed in non-compatible ways.
+ * @ingroup init
+ */
+#define GLFW_VERSION_MAJOR 3
+/*! @brief The minor version number of the GLFW library.
+ *
+ * This is incremented when features are added to the API but it remains
+ * backward-compatible.
+ * @ingroup init
+ */
+#define GLFW_VERSION_MINOR 2
+/*! @brief The revision number of the GLFW library.
+ *
+ * This is incremented when a bug fix release is made that does not contain any
+ * API changes.
+ * @ingroup init
+ */
+#define GLFW_VERSION_REVISION 0
+/*! @} */
+
+/*! @name Boolean values
+ * @{ */
+/*! @brief One.
+ *
+ * One. Seriously. You don't _need_ to use this symbol in your code. It's
+ * just semantic sugar for the number 1. You can use `1` or `true` or `_True`
+ * or `GL_TRUE` or whatever you want.
+ */
+#define GLFW_TRUE 1
+/*! @brief Zero.
+ *
+ * Zero. Seriously. You don't _need_ to use this symbol in your code. It's
+ * just just semantic sugar for the number 0. You can use `0` or `false` or
+ * `_False` or `GL_FALSE` or whatever you want.
+ */
+#define GLFW_FALSE 0
+/*! @} */
+
+/*! @name Key and button actions
+ * @{ */
+/*! @brief The key or mouse button was released.
+ *
+ * The key or mouse button was released.
+ *
+ * @ingroup input
+ */
+#define GLFW_RELEASE 0
+/*! @brief The key or mouse button was pressed.
+ *
+ * The key or mouse button was pressed.
+ *
+ * @ingroup input
+ */
+#define GLFW_PRESS 1
+/*! @brief The key was held down until it repeated.
+ *
+ * The key was held down until it repeated.
+ *
+ * @ingroup input
+ */
+#define GLFW_REPEAT 2
+/*! @} */
+
+/*! @defgroup keys Keyboard keys
+ *
+ * See [key input](@ref input_key) for how these are used.
+ *
+ * These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60),
+ * but re-arranged to map to 7-bit ASCII for printable keys (function keys are
+ * put in the 256+ range).
+ *
+ * The naming of the key codes follow these rules:
+ * - The US keyboard layout is used
+ * - Names of printable alpha-numeric characters are used (e.g. "A", "R",
+ * "3", etc.)
+ * - For non-alphanumeric characters, Unicode:ish names are used (e.g.
+ * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not
+ * correspond to the Unicode standard (usually for brevity)
+ * - Keys that lack a clear US mapping are named "WORLD_x"
+ * - For non-printable keys, custom names are used (e.g. "F4",
+ * "BACKSPACE", etc.)
+ *
+ * @ingroup input
+ * @{
+ */
+
+/* The unknown key */
+#define GLFW_KEY_UNKNOWN -1
+
+/* Printable keys */
+#define GLFW_KEY_SPACE 32
+#define GLFW_KEY_APOSTROPHE 39 /* ' */
+#define GLFW_KEY_COMMA 44 /* , */
+#define GLFW_KEY_MINUS 45 /* - */
+#define GLFW_KEY_PERIOD 46 /* . */
+#define GLFW_KEY_SLASH 47 /* / */
+#define GLFW_KEY_0 48
+#define GLFW_KEY_1 49
+#define GLFW_KEY_2 50
+#define GLFW_KEY_3 51
+#define GLFW_KEY_4 52
+#define GLFW_KEY_5 53
+#define GLFW_KEY_6 54
+#define GLFW_KEY_7 55
+#define GLFW_KEY_8 56
+#define GLFW_KEY_9 57
+#define GLFW_KEY_SEMICOLON 59 /* ; */
+#define GLFW_KEY_EQUAL 61 /* = */
+#define GLFW_KEY_A 65
+#define GLFW_KEY_B 66
+#define GLFW_KEY_C 67
+#define GLFW_KEY_D 68
+#define GLFW_KEY_E 69
+#define GLFW_KEY_F 70
+#define GLFW_KEY_G 71
+#define GLFW_KEY_H 72
+#define GLFW_KEY_I 73
+#define GLFW_KEY_J 74
+#define GLFW_KEY_K 75
+#define GLFW_KEY_L 76
+#define GLFW_KEY_M 77
+#define GLFW_KEY_N 78
+#define GLFW_KEY_O 79
+#define GLFW_KEY_P 80
+#define GLFW_KEY_Q 81
+#define GLFW_KEY_R 82
+#define GLFW_KEY_S 83
+#define GLFW_KEY_T 84
+#define GLFW_KEY_U 85
+#define GLFW_KEY_V 86
+#define GLFW_KEY_W 87
+#define GLFW_KEY_X 88
+#define GLFW_KEY_Y 89
+#define GLFW_KEY_Z 90
+#define GLFW_KEY_LEFT_BRACKET 91 /* [ */
+#define GLFW_KEY_BACKSLASH 92 /* \ */
+#define GLFW_KEY_RIGHT_BRACKET 93 /* ] */
+#define GLFW_KEY_GRAVE_ACCENT 96 /* ` */
+#define GLFW_KEY_WORLD_1 161 /* non-US #1 */
+#define GLFW_KEY_WORLD_2 162 /* non-US #2 */
+
+/* Function keys */
+#define GLFW_KEY_ESCAPE 256
+#define GLFW_KEY_ENTER 257
+#define GLFW_KEY_TAB 258
+#define GLFW_KEY_BACKSPACE 259
+#define GLFW_KEY_INSERT 260
+#define GLFW_KEY_DELETE 261
+#define GLFW_KEY_RIGHT 262
+#define GLFW_KEY_LEFT 263
+#define GLFW_KEY_DOWN 264
+#define GLFW_KEY_UP 265
+#define GLFW_KEY_PAGE_UP 266
+#define GLFW_KEY_PAGE_DOWN 267
+#define GLFW_KEY_HOME 268
+#define GLFW_KEY_END 269
+#define GLFW_KEY_CAPS_LOCK 280
+#define GLFW_KEY_SCROLL_LOCK 281
+#define GLFW_KEY_NUM_LOCK 282
+#define GLFW_KEY_PRINT_SCREEN 283
+#define GLFW_KEY_PAUSE 284
+#define GLFW_KEY_F1 290
+#define GLFW_KEY_F2 291
+#define GLFW_KEY_F3 292
+#define GLFW_KEY_F4 293
+#define GLFW_KEY_F5 294
+#define GLFW_KEY_F6 295
+#define GLFW_KEY_F7 296
+#define GLFW_KEY_F8 297
+#define GLFW_KEY_F9 298
+#define GLFW_KEY_F10 299
+#define GLFW_KEY_F11 300
+#define GLFW_KEY_F12 301
+#define GLFW_KEY_F13 302
+#define GLFW_KEY_F14 303
+#define GLFW_KEY_F15 304
+#define GLFW_KEY_F16 305
+#define GLFW_KEY_F17 306
+#define GLFW_KEY_F18 307
+#define GLFW_KEY_F19 308
+#define GLFW_KEY_F20 309
+#define GLFW_KEY_F21 310
+#define GLFW_KEY_F22 311
+#define GLFW_KEY_F23 312
+#define GLFW_KEY_F24 313
+#define GLFW_KEY_F25 314
+#define GLFW_KEY_KP_0 320
+#define GLFW_KEY_KP_1 321
+#define GLFW_KEY_KP_2 322
+#define GLFW_KEY_KP_3 323
+#define GLFW_KEY_KP_4 324
+#define GLFW_KEY_KP_5 325
+#define GLFW_KEY_KP_6 326
+#define GLFW_KEY_KP_7 327
+#define GLFW_KEY_KP_8 328
+#define GLFW_KEY_KP_9 329
+#define GLFW_KEY_KP_DECIMAL 330
+#define GLFW_KEY_KP_DIVIDE 331
+#define GLFW_KEY_KP_MULTIPLY 332
+#define GLFW_KEY_KP_SUBTRACT 333
+#define GLFW_KEY_KP_ADD 334
+#define GLFW_KEY_KP_ENTER 335
+#define GLFW_KEY_KP_EQUAL 336
+#define GLFW_KEY_LEFT_SHIFT 340
+#define GLFW_KEY_LEFT_CONTROL 341
+#define GLFW_KEY_LEFT_ALT 342
+#define GLFW_KEY_LEFT_SUPER 343
+#define GLFW_KEY_RIGHT_SHIFT 344
+#define GLFW_KEY_RIGHT_CONTROL 345
+#define GLFW_KEY_RIGHT_ALT 346
+#define GLFW_KEY_RIGHT_SUPER 347
+#define GLFW_KEY_MENU 348
+
+#define GLFW_KEY_LAST GLFW_KEY_MENU
+
+/*! @} */
+
+/*! @defgroup mods Modifier key flags
+ *
+ * See [key input](@ref input_key) for how these are used.
+ *
+ * @ingroup input
+ * @{ */
+
+/*! @brief If this bit is set one or more Shift keys were held down.
+ */
+#define GLFW_MOD_SHIFT 0x0001
+/*! @brief If this bit is set one or more Control keys were held down.
+ */
+#define GLFW_MOD_CONTROL 0x0002
+/*! @brief If this bit is set one or more Alt keys were held down.
+ */
+#define GLFW_MOD_ALT 0x0004
+/*! @brief If this bit is set one or more Super keys were held down.
+ */
+#define GLFW_MOD_SUPER 0x0008
+
+/*! @} */
+
+/*! @defgroup buttons Mouse buttons
+ *
+ * See [mouse button input](@ref input_mouse_button) for how these are used.
+ *
+ * @ingroup input
+ * @{ */
+#define GLFW_MOUSE_BUTTON_1 0
+#define GLFW_MOUSE_BUTTON_2 1
+#define GLFW_MOUSE_BUTTON_3 2
+#define GLFW_MOUSE_BUTTON_4 3
+#define GLFW_MOUSE_BUTTON_5 4
+#define GLFW_MOUSE_BUTTON_6 5
+#define GLFW_MOUSE_BUTTON_7 6
+#define GLFW_MOUSE_BUTTON_8 7
+#define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8
+#define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1
+#define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2
+#define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3
+/*! @} */
+
+/*! @defgroup joysticks Joysticks
+ *
+ * See [joystick input](@ref joystick) for how these are used.
+ *
+ * @ingroup input
+ * @{ */
+#define GLFW_JOYSTICK_1 0
+#define GLFW_JOYSTICK_2 1
+#define GLFW_JOYSTICK_3 2
+#define GLFW_JOYSTICK_4 3
+#define GLFW_JOYSTICK_5 4
+#define GLFW_JOYSTICK_6 5
+#define GLFW_JOYSTICK_7 6
+#define GLFW_JOYSTICK_8 7
+#define GLFW_JOYSTICK_9 8
+#define GLFW_JOYSTICK_10 9
+#define GLFW_JOYSTICK_11 10
+#define GLFW_JOYSTICK_12 11
+#define GLFW_JOYSTICK_13 12
+#define GLFW_JOYSTICK_14 13
+#define GLFW_JOYSTICK_15 14
+#define GLFW_JOYSTICK_16 15
+#define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16
+/*! @} */
+
+/*! @defgroup errors Error codes
+ *
+ * See [error handling](@ref error_handling) for how these are used.
+ *
+ * @ingroup init
+ * @{ */
+/*! @brief GLFW has not been initialized.
+ *
+ * This occurs if a GLFW function was called that must not be called unless the
+ * library is [initialized](@ref intro_init).
+ *
+ * @analysis Application programmer error. Initialize GLFW before calling any
+ * function that requires initialization.
+ */
+#define GLFW_NOT_INITIALIZED 0x00010001
+/*! @brief No context is current for this thread.
+ *
+ * This occurs if a GLFW function was called that needs and operates on the
+ * current OpenGL or OpenGL ES context but no context is current on the calling
+ * thread. One such function is @ref glfwSwapInterval.
+ *
+ * @analysis Application programmer error. Ensure a context is current before
+ * calling functions that require a current context.
+ */
+#define GLFW_NO_CURRENT_CONTEXT 0x00010002
+/*! @brief One of the arguments to the function was an invalid enum value.
+ *
+ * One of the arguments to the function was an invalid enum value, for example
+ * requesting [GLFW_RED_BITS](@ref window_hints_fb) with @ref
+ * glfwGetWindowAttrib.
+ *
+ * @analysis Application programmer error. Fix the offending call.
+ */
+#define GLFW_INVALID_ENUM 0x00010003
+/*! @brief One of the arguments to the function was an invalid value.
+ *
+ * One of the arguments to the function was an invalid value, for example
+ * requesting a non-existent OpenGL or OpenGL ES version like 2.7.
+ *
+ * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead
+ * result in a @ref GLFW_VERSION_UNAVAILABLE error.
+ *
+ * @analysis Application programmer error. Fix the offending call.
+ */
+#define GLFW_INVALID_VALUE 0x00010004
+/*! @brief A memory allocation failed.
+ *
+ * A memory allocation failed.
+ *
+ * @analysis A bug in GLFW or the underlying operating system. Report the bug
+ * to our [issue tracker](https://github.com/glfw/glfw/issues).
+ */
+#define GLFW_OUT_OF_MEMORY 0x00010005
+/*! @brief GLFW could not find support for the requested API on the system.
+ *
+ * GLFW could not find support for the requested API on the system.
+ *
+ * @analysis The installed graphics driver does not support the requested
+ * API, or does not support it via the chosen context creation backend.
+ * Below are a few examples.
+ *
+ * @par
+ * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only
+ * supports OpenGL ES via EGL, while Nvidia and Intel only support it via
+ * a WGL or GLX extension. OS X does not provide OpenGL ES at all. The Mesa
+ * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary
+ * driver. Older graphics drivers do not support Vulkan.
+ */
+#define GLFW_API_UNAVAILABLE 0x00010006
+/*! @brief The requested OpenGL or OpenGL ES version is not available.
+ *
+ * The requested OpenGL or OpenGL ES version (including any requested context
+ * or framebuffer hints) is not available on this machine.
+ *
+ * @analysis The machine does not support your requirements. If your
+ * application is sufficiently flexible, downgrade your requirements and try
+ * again. Otherwise, inform the user that their machine does not match your
+ * requirements.
+ *
+ * @par
+ * Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0
+ * comes out before the 4.x series gets that far, also fail with this error and
+ * not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions
+ * will exist.
+ */
+#define GLFW_VERSION_UNAVAILABLE 0x00010007
+/*! @brief A platform-specific error occurred that does not match any of the
+ * more specific categories.
+ *
+ * A platform-specific error occurred that does not match any of the more
+ * specific categories.
+ *
+ * @analysis A bug or configuration error in GLFW, the underlying operating
+ * system or its drivers, or a lack of required resources. Report the issue to
+ * our [issue tracker](https://github.com/glfw/glfw/issues).
+ */
+#define GLFW_PLATFORM_ERROR 0x00010008
+/*! @brief The requested format is not supported or available.
+ *
+ * If emitted during window creation, the requested pixel format is not
+ * supported.
+ *
+ * If emitted when querying the clipboard, the contents of the clipboard could
+ * not be converted to the requested format.
+ *
+ * @analysis If emitted during window creation, one or more
+ * [hard constraints](@ref window_hints_hard) did not match any of the
+ * available pixel formats. If your application is sufficiently flexible,
+ * downgrade your requirements and try again. Otherwise, inform the user that
+ * their machine does not match your requirements.
+ *
+ * @par
+ * If emitted when querying the clipboard, ignore the error or report it to
+ * the user, as appropriate.
+ */
+#define GLFW_FORMAT_UNAVAILABLE 0x00010009
+/*! @brief The specified window does not have an OpenGL or OpenGL ES context.
+ *
+ * A window that does not have an OpenGL or OpenGL ES context was passed to
+ * a function that requires it to have one.
+ *
+ * @analysis Application programmer error. Fix the offending call.
+ */
+#define GLFW_NO_WINDOW_CONTEXT 0x0001000A
+/*! @} */
+
+#define GLFW_FOCUSED 0x00020001
+#define GLFW_ICONIFIED 0x00020002
+#define GLFW_RESIZABLE 0x00020003
+#define GLFW_VISIBLE 0x00020004
+#define GLFW_DECORATED 0x00020005
+#define GLFW_AUTO_ICONIFY 0x00020006
+#define GLFW_FLOATING 0x00020007
+#define GLFW_MAXIMIZED 0x00020008
+
+#define GLFW_RED_BITS 0x00021001
+#define GLFW_GREEN_BITS 0x00021002
+#define GLFW_BLUE_BITS 0x00021003
+#define GLFW_ALPHA_BITS 0x00021004
+#define GLFW_DEPTH_BITS 0x00021005
+#define GLFW_STENCIL_BITS 0x00021006
+#define GLFW_ACCUM_RED_BITS 0x00021007
+#define GLFW_ACCUM_GREEN_BITS 0x00021008
+#define GLFW_ACCUM_BLUE_BITS 0x00021009
+#define GLFW_ACCUM_ALPHA_BITS 0x0002100A
+#define GLFW_AUX_BUFFERS 0x0002100B
+#define GLFW_STEREO 0x0002100C
+#define GLFW_SAMPLES 0x0002100D
+#define GLFW_SRGB_CAPABLE 0x0002100E
+#define GLFW_REFRESH_RATE 0x0002100F
+#define GLFW_DOUBLEBUFFER 0x00021010
+
+#define GLFW_CLIENT_API 0x00022001
+#define GLFW_CONTEXT_VERSION_MAJOR 0x00022002
+#define GLFW_CONTEXT_VERSION_MINOR 0x00022003
+#define GLFW_CONTEXT_REVISION 0x00022004
+#define GLFW_CONTEXT_ROBUSTNESS 0x00022005
+#define GLFW_OPENGL_FORWARD_COMPAT 0x00022006
+#define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007
+#define GLFW_OPENGL_PROFILE 0x00022008
+#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009
+#define GLFW_CONTEXT_NO_ERROR 0x0002200A
+#define GLFW_CONTEXT_CREATION_API 0x0002200B
+
+#define GLFW_NO_API 0
+#define GLFW_OPENGL_API 0x00030001
+#define GLFW_OPENGL_ES_API 0x00030002
+
+#define GLFW_NO_ROBUSTNESS 0
+#define GLFW_NO_RESET_NOTIFICATION 0x00031001
+#define GLFW_LOSE_CONTEXT_ON_RESET 0x00031002
+
+#define GLFW_OPENGL_ANY_PROFILE 0
+#define GLFW_OPENGL_CORE_PROFILE 0x00032001
+#define GLFW_OPENGL_COMPAT_PROFILE 0x00032002
+
+#define GLFW_CURSOR 0x00033001
+#define GLFW_STICKY_KEYS 0x00033002
+#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003
+
+#define GLFW_CURSOR_NORMAL 0x00034001
+#define GLFW_CURSOR_HIDDEN 0x00034002
+#define GLFW_CURSOR_DISABLED 0x00034003
+
+#define GLFW_ANY_RELEASE_BEHAVIOR 0
+#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001
+#define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002
+
+#define GLFW_NATIVE_CONTEXT_API 0x00036001
+#define GLFW_EGL_CONTEXT_API 0x00036002
+
+/*! @defgroup shapes Standard cursor shapes
+ *
+ * See [standard cursor creation](@ref cursor_standard) for how these are used.
+ *
+ * @ingroup input
+ * @{ */
+
+/*! @brief The regular arrow cursor shape.
+ *
+ * The regular arrow cursor.
+ */
+#define GLFW_ARROW_CURSOR 0x00036001
+/*! @brief The text input I-beam cursor shape.
+ *
+ * The text input I-beam cursor shape.
+ */
+#define GLFW_IBEAM_CURSOR 0x00036002
+/*! @brief The crosshair shape.
+ *
+ * The crosshair shape.
+ */
+#define GLFW_CROSSHAIR_CURSOR 0x00036003
+/*! @brief The hand shape.
+ *
+ * The hand shape.
+ */
+#define GLFW_HAND_CURSOR 0x00036004
+/*! @brief The horizontal resize arrow shape.
+ *
+ * The horizontal resize arrow shape.
+ */
+#define GLFW_HRESIZE_CURSOR 0x00036005
+/*! @brief The vertical resize arrow shape.
+ *
+ * The vertical resize arrow shape.
+ */
+#define GLFW_VRESIZE_CURSOR 0x00036006
+/*! @} */
+
+#define GLFW_CONNECTED 0x00040001
+#define GLFW_DISCONNECTED 0x00040002
+
+#define GLFW_DONT_CARE -1
+
+
+/*************************************************************************
+ * GLFW API types
+ *************************************************************************/
+
+/*! @brief Client API function pointer type.
+ *
+ * Generic function pointer used for returning client API function pointers
+ * without forcing a cast from a regular pointer.
+ *
+ * @sa @ref context_glext
+ * @sa glfwGetProcAddress
+ *
+ * @since Added in version 3.0.
+
+ * @ingroup context
+ */
+typedef void (*GLFWglproc)(void);
+
+/*! @brief Vulkan API function pointer type.
+ *
+ * Generic function pointer used for returning Vulkan API function pointers
+ * without forcing a cast from a regular pointer.
+ *
+ * @sa @ref vulkan_proc
+ * @sa glfwGetInstanceProcAddress
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup vulkan
+ */
+typedef void (*GLFWvkproc)(void);
+
+/*! @brief Opaque monitor object.
+ *
+ * Opaque monitor object.
+ *
+ * @see @ref monitor_object
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup monitor
+ */
+typedef struct GLFWmonitor GLFWmonitor;
+
+/*! @brief Opaque window object.
+ *
+ * Opaque window object.
+ *
+ * @see @ref window_object
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+typedef struct GLFWwindow GLFWwindow;
+
+/*! @brief Opaque cursor object.
+ *
+ * Opaque cursor object.
+ *
+ * @see @ref cursor_object
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup cursor
+ */
+typedef struct GLFWcursor GLFWcursor;
+
+/*! @brief The function signature for error callbacks.
+ *
+ * This is the function signature for error callback functions.
+ *
+ * @param[in] error An [error code](@ref errors).
+ * @param[in] description A UTF-8 encoded string describing the error.
+ *
+ * @sa @ref error_handling
+ * @sa glfwSetErrorCallback
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup init
+ */
+typedef void (* GLFWerrorfun)(int,const char*);
+
+/*! @brief The function signature for window position callbacks.
+ *
+ * This is the function signature for window position callback functions.
+ *
+ * @param[in] window The window that was moved.
+ * @param[in] xpos The new x-coordinate, in screen coordinates, of the
+ * upper-left corner of the client area of the window.
+ * @param[in] ypos The new y-coordinate, in screen coordinates, of the
+ * upper-left corner of the client area of the window.
+ *
+ * @sa @ref window_pos
+ * @sa glfwSetWindowPosCallback
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int);
+
+/*! @brief The function signature for window resize callbacks.
+ *
+ * This is the function signature for window size callback functions.
+ *
+ * @param[in] window The window that was resized.
+ * @param[in] width The new width, in screen coordinates, of the window.
+ * @param[in] height The new height, in screen coordinates, of the window.
+ *
+ * @sa @ref window_size
+ * @sa glfwSetWindowSizeCallback
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup window
+ */
+typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int);
+
+/*! @brief The function signature for window close callbacks.
+ *
+ * This is the function signature for window close callback functions.
+ *
+ * @param[in] window The window that the user attempted to close.
+ *
+ * @sa @ref window_close
+ * @sa glfwSetWindowCloseCallback
+ *
+ * @since Added in version 2.5.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup window
+ */
+typedef void (* GLFWwindowclosefun)(GLFWwindow*);
+
+/*! @brief The function signature for window content refresh callbacks.
+ *
+ * This is the function signature for window refresh callback functions.
+ *
+ * @param[in] window The window whose content needs to be refreshed.
+ *
+ * @sa @ref window_refresh
+ * @sa glfwSetWindowRefreshCallback
+ *
+ * @since Added in version 2.5.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup window
+ */
+typedef void (* GLFWwindowrefreshfun)(GLFWwindow*);
+
+/*! @brief The function signature for window focus/defocus callbacks.
+ *
+ * This is the function signature for window focus callback functions.
+ *
+ * @param[in] window The window that gained or lost input focus.
+ * @param[in] focused `GLFW_TRUE` if the window was given input focus, or
+ * `GLFW_FALSE` if it lost it.
+ *
+ * @sa @ref window_focus
+ * @sa glfwSetWindowFocusCallback
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int);
+
+/*! @brief The function signature for window iconify/restore callbacks.
+ *
+ * This is the function signature for window iconify/restore callback
+ * functions.
+ *
+ * @param[in] window The window that was iconified or restored.
+ * @param[in] iconified `GLFW_TRUE` if the window was iconified, or
+ * `GLFW_FALSE` if it was restored.
+ *
+ * @sa @ref window_iconify
+ * @sa glfwSetWindowIconifyCallback
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int);
+
+/*! @brief The function signature for framebuffer resize callbacks.
+ *
+ * This is the function signature for framebuffer resize callback
+ * functions.
+ *
+ * @param[in] window The window whose framebuffer was resized.
+ * @param[in] width The new width, in pixels, of the framebuffer.
+ * @param[in] height The new height, in pixels, of the framebuffer.
+ *
+ * @sa @ref window_fbsize
+ * @sa glfwSetFramebufferSizeCallback
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int);
+
+/*! @brief The function signature for mouse button callbacks.
+ *
+ * This is the function signature for mouse button callback functions.
+ *
+ * @param[in] window The window that received the event.
+ * @param[in] button The [mouse button](@ref buttons) that was pressed or
+ * released.
+ * @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`.
+ * @param[in] mods Bit field describing which [modifier keys](@ref mods) were
+ * held down.
+ *
+ * @sa @ref input_mouse_button
+ * @sa glfwSetMouseButtonCallback
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle and modifier mask parameters.
+ *
+ * @ingroup input
+ */
+typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int);
+
+/*! @brief The function signature for cursor position callbacks.
+ *
+ * This is the function signature for cursor position callback functions.
+ *
+ * @param[in] window The window that received the event.
+ * @param[in] xpos The new cursor x-coordinate, relative to the left edge of
+ * the client area.
+ * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the
+ * client area.
+ *
+ * @sa @ref cursor_pos
+ * @sa glfwSetCursorPosCallback
+ *
+ * @since Added in version 3.0. Replaces `GLFWmouseposfun`.
+ *
+ * @ingroup input
+ */
+typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double);
+
+/*! @brief The function signature for cursor enter/leave callbacks.
+ *
+ * This is the function signature for cursor enter/leave callback functions.
+ *
+ * @param[in] window The window that received the event.
+ * @param[in] entered `GLFW_TRUE` if the cursor entered the window's client
+ * area, or `GLFW_FALSE` if it left it.
+ *
+ * @sa @ref cursor_enter
+ * @sa glfwSetCursorEnterCallback
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup input
+ */
+typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
+
+/*! @brief The function signature for scroll callbacks.
+ *
+ * This is the function signature for scroll callback functions.
+ *
+ * @param[in] window The window that received the event.
+ * @param[in] xoffset The scroll offset along the x-axis.
+ * @param[in] yoffset The scroll offset along the y-axis.
+ *
+ * @sa @ref scrolling
+ * @sa glfwSetScrollCallback
+ *
+ * @since Added in version 3.0. Replaces `GLFWmousewheelfun`.
+ *
+ * @ingroup input
+ */
+typedef void (* GLFWscrollfun)(GLFWwindow*,double,double);
+
+/*! @brief The function signature for keyboard key callbacks.
+ *
+ * This is the function signature for keyboard key callback functions.
+ *
+ * @param[in] window The window that received the event.
+ * @param[in] key The [keyboard key](@ref keys) that was pressed or released.
+ * @param[in] scancode The system-specific scancode of the key.
+ * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`.
+ * @param[in] mods Bit field describing which [modifier keys](@ref mods) were
+ * held down.
+ *
+ * @sa @ref input_key
+ * @sa glfwSetKeyCallback
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle, scancode and modifier mask parameters.
+ *
+ * @ingroup input
+ */
+typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int);
+
+/*! @brief The function signature for Unicode character callbacks.
+ *
+ * This is the function signature for Unicode character callback functions.
+ *
+ * @param[in] window The window that received the event.
+ * @param[in] codepoint The Unicode code point of the character.
+ *
+ * @sa @ref input_char
+ * @sa glfwSetCharCallback
+ *
+ * @since Added in version 2.4.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup input
+ */
+typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int);
+
+/*! @brief The function signature for Unicode character with modifiers
+ * callbacks.
+ *
+ * This is the function signature for Unicode character with modifiers callback
+ * functions. It is called for each input character, regardless of what
+ * modifier keys are held down.
+ *
+ * @param[in] window The window that received the event.
+ * @param[in] codepoint The Unicode code point of the character.
+ * @param[in] mods Bit field describing which [modifier keys](@ref mods) were
+ * held down.
+ *
+ * @sa @ref input_char
+ * @sa glfwSetCharModsCallback
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup input
+ */
+typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int);
+
+/*! @brief The function signature for file drop callbacks.
+ *
+ * This is the function signature for file drop callbacks.
+ *
+ * @param[in] window The window that received the event.
+ * @param[in] count The number of dropped files.
+ * @param[in] paths The UTF-8 encoded file and/or directory path names.
+ *
+ * @sa @ref path_drop
+ * @sa glfwSetDropCallback
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup input
+ */
+typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**);
+
+/*! @brief The function signature for monitor configuration callbacks.
+ *
+ * This is the function signature for monitor configuration callback functions.
+ *
+ * @param[in] monitor The monitor that was connected or disconnected.
+ * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`.
+ *
+ * @sa @ref monitor_event
+ * @sa glfwSetMonitorCallback
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup monitor
+ */
+typedef void (* GLFWmonitorfun)(GLFWmonitor*,int);
+
+/*! @brief The function signature for joystick configuration callbacks.
+ *
+ * This is the function signature for joystick configuration callback
+ * functions.
+ *
+ * @param[in] joy The joystick that was connected or disconnected.
+ * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`.
+ *
+ * @sa @ref joystick_event
+ * @sa glfwSetJoystickCallback
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup input
+ */
+typedef void (* GLFWjoystickfun)(int,int);
+
+/*! @brief Video mode type.
+ *
+ * This describes a single video mode.
+ *
+ * @sa @ref monitor_modes
+ * @sa glfwGetVideoMode glfwGetVideoModes
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added refresh rate member.
+ *
+ * @ingroup monitor
+ */
+typedef struct GLFWvidmode
+{
+ /*! The width, in screen coordinates, of the video mode.
+ */
+ int width;
+ /*! The height, in screen coordinates, of the video mode.
+ */
+ int height;
+ /*! The bit depth of the red channel of the video mode.
+ */
+ int redBits;
+ /*! The bit depth of the green channel of the video mode.
+ */
+ int greenBits;
+ /*! The bit depth of the blue channel of the video mode.
+ */
+ int blueBits;
+ /*! The refresh rate, in Hz, of the video mode.
+ */
+ int refreshRate;
+} GLFWvidmode;
+
+/*! @brief Gamma ramp.
+ *
+ * This describes the gamma ramp for a monitor.
+ *
+ * @sa @ref monitor_gamma
+ * @sa glfwGetGammaRamp glfwSetGammaRamp
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup monitor
+ */
+typedef struct GLFWgammaramp
+{
+ /*! An array of value describing the response of the red channel.
+ */
+ unsigned short* red;
+ /*! An array of value describing the response of the green channel.
+ */
+ unsigned short* green;
+ /*! An array of value describing the response of the blue channel.
+ */
+ unsigned short* blue;
+ /*! The number of elements in each array.
+ */
+ unsigned int size;
+} GLFWgammaramp;
+
+/*! @brief Image data.
+ *
+ * @sa @ref cursor_custom
+ *
+ * @since Added in version 2.1.
+ * @glfw3 Removed format and bytes-per-pixel members.
+ */
+typedef struct GLFWimage
+{
+ /*! The width, in pixels, of this image.
+ */
+ int width;
+ /*! The height, in pixels, of this image.
+ */
+ int height;
+ /*! The pixel data of this image, arranged left-to-right, top-to-bottom.
+ */
+ unsigned char* pixels;
+} GLFWimage;
+
+
+/*************************************************************************
+ * GLFW API functions
+ *************************************************************************/
+
+/*! @brief Initializes the GLFW library.
+ *
+ * This function initializes the GLFW library. Before most GLFW functions can
+ * be used, GLFW must be initialized, and before an application terminates GLFW
+ * should be terminated in order to free any resources allocated during or
+ * after initialization.
+ *
+ * If this function fails, it calls @ref glfwTerminate before returning. If it
+ * succeeds, you should call @ref glfwTerminate before the application exits.
+ *
+ * Additional calls to this function after successful initialization but before
+ * termination will return `GLFW_TRUE` immediately.
+ *
+ * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_PLATFORM_ERROR.
+ *
+ * @remark @osx This function will change the current directory of the
+ * application to the `Contents/Resources` subdirectory of the application's
+ * bundle, if present. This can be disabled with a
+ * [compile-time option](@ref compile_options_osx).
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref intro_init
+ * @sa glfwTerminate
+ *
+ * @since Added in version 1.0.
+ *
+ * @ingroup init
+ */
+GLFWAPI int glfwInit(void);
+
+/*! @brief Terminates the GLFW library.
+ *
+ * This function destroys all remaining windows and cursors, restores any
+ * modified gamma ramps and frees any other allocated resources. Once this
+ * function is called, you must again call @ref glfwInit successfully before
+ * you will be able to use most GLFW functions.
+ *
+ * If GLFW has been successfully initialized, this function should be called
+ * before the application exits. If initialization fails, there is no need to
+ * call this function, as it is called by @ref glfwInit before it returns
+ * failure.
+ *
+ * @errors Possible errors include @ref GLFW_PLATFORM_ERROR.
+ *
+ * @remark This function may be called before @ref glfwInit.
+ *
+ * @warning The contexts of any remaining windows must not be current on any
+ * other thread when this function is called.
+ *
+ * @reentrancy This function must not be called from a callback.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref intro_init
+ * @sa glfwInit
+ *
+ * @since Added in version 1.0.
+ *
+ * @ingroup init
+ */
+GLFWAPI void glfwTerminate(void);
+
+/*! @brief Retrieves the version of the GLFW library.
+ *
+ * This function retrieves the major, minor and revision numbers of the GLFW
+ * library. It is intended for when you are using GLFW as a shared library and
+ * want to ensure that you are using the minimum required version.
+ *
+ * Any or all of the version arguments may be `NULL`.
+ *
+ * @param[out] major Where to store the major version number, or `NULL`.
+ * @param[out] minor Where to store the minor version number, or `NULL`.
+ * @param[out] rev Where to store the revision number, or `NULL`.
+ *
+ * @errors None.
+ *
+ * @remark This function may be called before @ref glfwInit.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref intro_version
+ * @sa glfwGetVersionString
+ *
+ * @since Added in version 1.0.
+ *
+ * @ingroup init
+ */
+GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev);
+
+/*! @brief Returns a string describing the compile-time configuration.
+ *
+ * This function returns the compile-time generated
+ * [version string](@ref intro_version_string) of the GLFW library binary. It
+ * describes the version, platform, compiler and any platform-specific
+ * compile-time options. It should not be confused with the OpenGL or OpenGL
+ * ES version string, queried with `glGetString`.
+ *
+ * __Do not use the version string__ to parse the GLFW library version. The
+ * @ref glfwGetVersion function provides the version of the running library
+ * binary in numerical format.
+ *
+ * @return The ASCII encoded GLFW version string.
+ *
+ * @errors None.
+ *
+ * @remark This function may be called before @ref glfwInit.
+ *
+ * @pointer_lifetime The returned string is static and compile-time generated.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref intro_version
+ * @sa glfwGetVersion
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup init
+ */
+GLFWAPI const char* glfwGetVersionString(void);
+
+/*! @brief Sets the error callback.
+ *
+ * This function sets the error callback, which is called with an error code
+ * and a human-readable description each time a GLFW error occurs.
+ *
+ * The error callback is called on the thread where the error occurred. If you
+ * are using GLFW from multiple threads, your error callback needs to be
+ * written accordingly.
+ *
+ * Because the description string may have been generated specifically for that
+ * error, it is not guaranteed to be valid after the callback has returned. If
+ * you wish to use it after the callback returns, you need to make a copy.
+ *
+ * Once set, the error callback remains set even after the library has been
+ * terminated.
+ *
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set.
+ *
+ * @errors None.
+ *
+ * @remark This function may be called before @ref glfwInit.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref error_handling
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup init
+ */
+GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun);
+
+/*! @brief Returns the currently connected monitors.
+ *
+ * This function returns an array of handles for all currently connected
+ * monitors. The primary monitor is always first in the returned array. If no
+ * monitors were found, this function returns `NULL`.
+ *
+ * @param[out] count Where to store the number of monitors in the returned
+ * array. This is set to zero if an error occurred.
+ * @return An array of monitor handles, or `NULL` if no monitors were found or
+ * if an [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @pointer_lifetime The returned array is allocated and freed by GLFW. You
+ * should not free it yourself. It is guaranteed to be valid only until the
+ * monitor configuration changes or the library is terminated.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref monitor_monitors
+ * @sa @ref monitor_event
+ * @sa glfwGetPrimaryMonitor
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup monitor
+ */
+GLFWAPI GLFWmonitor** glfwGetMonitors(int* count);
+
+/*! @brief Returns the primary monitor.
+ *
+ * This function returns the primary monitor. This is usually the monitor
+ * where elements like the task bar or global menu bar are located.
+ *
+ * @return The primary monitor, or `NULL` if no monitors were found or if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @remark The primary monitor is always first in the array returned by @ref
+ * glfwGetMonitors.
+ *
+ * @sa @ref monitor_monitors
+ * @sa glfwGetMonitors
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup monitor
+ */
+GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void);
+
+/*! @brief Returns the position of the monitor's viewport on the virtual screen.
+ *
+ * This function returns the position, in screen coordinates, of the upper-left
+ * corner of the specified monitor.
+ *
+ * Any or all of the position arguments may be `NULL`. If an error occurs, all
+ * non-`NULL` position arguments will be set to zero.
+ *
+ * @param[in] monitor The monitor to query.
+ * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`.
+ * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref monitor_properties
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup monitor
+ */
+GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos);
+
+/*! @brief Returns the physical size of the monitor.
+ *
+ * This function returns the size, in millimetres, of the display area of the
+ * specified monitor.
+ *
+ * Some systems do not provide accurate monitor size information, either
+ * because the monitor
+ * [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data)
+ * data is incorrect or because the driver does not report it accurately.
+ *
+ * Any or all of the size arguments may be `NULL`. If an error occurs, all
+ * non-`NULL` size arguments will be set to zero.
+ *
+ * @param[in] monitor The monitor to query.
+ * @param[out] widthMM Where to store the width, in millimetres, of the
+ * monitor's display area, or `NULL`.
+ * @param[out] heightMM Where to store the height, in millimetres, of the
+ * monitor's display area, or `NULL`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @remark @win32 calculates the returned physical size from the
+ * current resolution and system DPI instead of querying the monitor EDID data.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref monitor_properties
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup monitor
+ */
+GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM);
+
+/*! @brief Returns the name of the specified monitor.
+ *
+ * This function returns a human-readable name, encoded as UTF-8, of the
+ * specified monitor. The name typically reflects the make and model of the
+ * monitor and is not guaranteed to be unique among the connected monitors.
+ *
+ * @param[in] monitor The monitor to query.
+ * @return The UTF-8 encoded name of the monitor, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @pointer_lifetime The returned string is allocated and freed by GLFW. You
+ * should not free it yourself. It is valid until the specified monitor is
+ * disconnected or the library is terminated.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref monitor_properties
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup monitor
+ */
+GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor);
+
+/*! @brief Sets the monitor configuration callback.
+ *
+ * This function sets the monitor configuration callback, or removes the
+ * currently set callback. This is called when a monitor is connected to or
+ * disconnected from the system.
+ *
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref monitor_event
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup monitor
+ */
+GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun);
+
+/*! @brief Returns the available video modes for the specified monitor.
+ *
+ * This function returns an array of all video modes supported by the specified
+ * monitor. The returned array is sorted in ascending order, first by color
+ * bit depth (the sum of all channel depths) and then by resolution area (the
+ * product of width and height).
+ *
+ * @param[in] monitor The monitor to query.
+ * @param[out] count Where to store the number of video modes in the returned
+ * array. This is set to zero if an error occurred.
+ * @return An array of video modes, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @pointer_lifetime The returned array is allocated and freed by GLFW. You
+ * should not free it yourself. It is valid until the specified monitor is
+ * disconnected, this function is called again for that monitor or the library
+ * is terminated.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref monitor_modes
+ * @sa glfwGetVideoMode
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Changed to return an array of modes for a specific monitor.
+ *
+ * @ingroup monitor
+ */
+GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count);
+
+/*! @brief Returns the current mode of the specified monitor.
+ *
+ * This function returns the current video mode of the specified monitor. If
+ * you have created a full screen window for that monitor, the return value
+ * will depend on whether that window is iconified.
+ *
+ * @param[in] monitor The monitor to query.
+ * @return The current mode of the monitor, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @pointer_lifetime The returned array is allocated and freed by GLFW. You
+ * should not free it yourself. It is valid until the specified monitor is
+ * disconnected or the library is terminated.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref monitor_modes
+ * @sa glfwGetVideoModes
+ *
+ * @since Added in version 3.0. Replaces `glfwGetDesktopMode`.
+ *
+ * @ingroup monitor
+ */
+GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
+
+/*! @brief Generates a gamma ramp and sets it for the specified monitor.
+ *
+ * This function generates a 256-element gamma ramp from the specified exponent
+ * and then calls @ref glfwSetGammaRamp with it. The value must be a finite
+ * number greater than zero.
+ *
+ * @param[in] monitor The monitor whose gamma ramp to set.
+ * @param[in] gamma The desired exponent.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref monitor_gamma
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup monitor
+ */
+GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma);
+
+/*! @brief Returns the current gamma ramp for the specified monitor.
+ *
+ * This function returns the current gamma ramp of the specified monitor.
+ *
+ * @param[in] monitor The monitor to query.
+ * @return The current gamma ramp, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @pointer_lifetime The returned structure and its arrays are allocated and
+ * freed by GLFW. You should not free them yourself. They are valid until the
+ * specified monitor is disconnected, this function is called again for that
+ * monitor or the library is terminated.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref monitor_gamma
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup monitor
+ */
+GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor);
+
+/*! @brief Sets the current gamma ramp for the specified monitor.
+ *
+ * This function sets the current gamma ramp for the specified monitor. The
+ * original gamma ramp for that monitor is saved by GLFW the first time this
+ * function is called and is restored by @ref glfwTerminate.
+ *
+ * @param[in] monitor The monitor whose gamma ramp to set.
+ * @param[in] ramp The gamma ramp to use.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @remark Gamma ramp sizes other than 256 are not supported by all platforms
+ * or graphics hardware.
+ *
+ * @remark @win32 The gamma ramp size must be 256.
+ *
+ * @pointer_lifetime The specified gamma ramp is copied before this function
+ * returns.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref monitor_gamma
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup monitor
+ */
+GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp);
+
+/*! @brief Resets all window hints to their default values.
+ *
+ * This function resets all window hints to their
+ * [default values](@ref window_hints_values).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_hints
+ * @sa glfwWindowHint
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwDefaultWindowHints(void);
+
+/*! @brief Sets the specified window hint to the desired value.
+ *
+ * This function sets hints for the next call to @ref glfwCreateWindow. The
+ * hints, once set, retain their values until changed by a call to @ref
+ * glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is
+ * terminated.
+ *
+ * This function does not check whether the specified hint values are valid.
+ * If you set hints to invalid values this will instead be reported by the next
+ * call to @ref glfwCreateWindow.
+ *
+ * @param[in] hint The [window hint](@ref window_hints) to set.
+ * @param[in] value The new value of the window hint.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_INVALID_ENUM.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_hints
+ * @sa glfwDefaultWindowHints
+ *
+ * @since Added in version 3.0. Replaces `glfwOpenWindowHint`.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwWindowHint(int hint, int value);
+
+/*! @brief Creates a window and its associated context.
+ *
+ * This function creates a window and its associated OpenGL or OpenGL ES
+ * context. Most of the options controlling how the window and its context
+ * should be created are specified with [window hints](@ref window_hints).
+ *
+ * Successful creation does not change which context is current. Before you
+ * can use the newly created context, you need to
+ * [make it current](@ref context_current). For information about the `share`
+ * parameter, see @ref context_sharing.
+ *
+ * The created window, framebuffer and context may differ from what you
+ * requested, as not all parameters and hints are
+ * [hard constraints](@ref window_hints_hard). This includes the size of the
+ * window, especially for full screen windows. To query the actual attributes
+ * of the created window, framebuffer and context, see @ref
+ * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize.
+ *
+ * To create a full screen window, you need to specify the monitor the window
+ * will cover. If no monitor is specified, the window will be windowed mode.
+ * Unless you have a way for the user to choose a specific monitor, it is
+ * recommended that you pick the primary monitor. For more information on how
+ * to query connected monitors, see @ref monitor_monitors.
+ *
+ * For full screen windows, the specified size becomes the resolution of the
+ * window's _desired video mode_. As long as a full screen window is not
+ * iconified, the supported video mode most closely matching the desired video
+ * mode is set for the specified monitor. For more information about full
+ * screen windows, including the creation of so called _windowed full screen_
+ * or _borderless full screen_ windows, see @ref window_windowed_full_screen.
+ *
+ * By default, newly created windows use the placement recommended by the
+ * window system. To create the window at a specific position, make it
+ * initially invisible using the [GLFW_VISIBLE](@ref window_hints_wnd) window
+ * hint, set its [position](@ref window_pos) and then [show](@ref window_hide)
+ * it.
+ *
+ * As long as at least one full screen window is not iconified, the screensaver
+ * is prohibited from starting.
+ *
+ * Window systems put limits on window sizes. Very large or very small window
+ * dimensions may be overridden by the window system on creation. Check the
+ * actual [size](@ref window_size) after creation.
+ *
+ * The [swap interval](@ref buffer_swap) is not set during window creation and
+ * the initial value may vary depending on driver settings and defaults.
+ *
+ * @param[in] width The desired width, in screen coordinates, of the window.
+ * This must be greater than zero.
+ * @param[in] height The desired height, in screen coordinates, of the window.
+ * This must be greater than zero.
+ * @param[in] title The initial, UTF-8 encoded window title.
+ * @param[in] monitor The monitor to use for full screen mode, or `NULL` for
+ * windowed mode.
+ * @param[in] share The window whose context to share resources with, or `NULL`
+ * to not share resources.
+ * @return The handle of the created window, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref
+ * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @remark @win32 Window creation will fail if the Microsoft GDI software
+ * OpenGL implementation is the only one available.
+ *
+ * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it
+ * will be set as the initial icon for the window. If no such icon is present,
+ * the `IDI_WINLOGO` icon will be used instead. To set a different icon, see
+ * @ref glfwSetWindowIcon.
+ *
+ * @remark @win32 The context to share resources with must not be current on
+ * any other thread.
+ *
+ * @remark @osx The GLFW window has no icon, as it is not a document
+ * window, but the dock icon will be the same as the application bundle's icon.
+ * For more information on bundles, see the
+ * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
+ * in the Mac Developer Library.
+ *
+ * @remark @osx The first time a window is created the menu bar is populated
+ * with common commands like Hide, Quit and About. The About entry opens
+ * a minimal about dialog with information from the application's bundle. The
+ * menu bar can be disabled with a
+ * [compile-time option](@ref compile_options_osx).
+ *
+ * @remark @osx On OS X 10.10 and later the window frame will not be rendered
+ * at full resolution on Retina displays unless the `NSHighResolutionCapable`
+ * key is enabled in the application bundle's `Info.plist`. For more
+ * information, see
+ * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html)
+ * in the Mac Developer Library. The GLFW test and example programs use
+ * a custom `Info.plist` template for this, which can be found as
+ * `CMake/MacOSXBundleInfo.plist.in` in the source tree.
+ *
+ * @remark @x11 Some window managers will not respect the placement of
+ * initially hidden windows.
+ *
+ * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for
+ * a window to reach its requested state. This means you may not be able to
+ * query the final size, position or other attributes directly after window
+ * creation.
+ *
+ * @reentrancy This function must not be called from a callback.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_creation
+ * @sa glfwDestroyWindow
+ *
+ * @since Added in version 3.0. Replaces `glfwOpenWindow`.
+ *
+ * @ingroup window
+ */
+GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share);
+
+/*! @brief Destroys the specified window and its context.
+ *
+ * This function destroys the specified window and its context. On calling
+ * this function, no further callbacks will be called for that window.
+ *
+ * If the context of the specified window is current on the main thread, it is
+ * detached before being destroyed.
+ *
+ * @param[in] window The window to destroy.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @note The context of the specified window must not be current on any other
+ * thread when this function is called.
+ *
+ * @reentrancy This function must not be called from a callback.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_creation
+ * @sa glfwCreateWindow
+ *
+ * @since Added in version 3.0. Replaces `glfwCloseWindow`.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwDestroyWindow(GLFWwindow* window);
+
+/*! @brief Checks the close flag of the specified window.
+ *
+ * This function returns the value of the close flag of the specified window.
+ *
+ * @param[in] window The window to query.
+ * @return The value of the close flag.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @sa @ref window_close
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI int glfwWindowShouldClose(GLFWwindow* window);
+
+/*! @brief Sets the close flag of the specified window.
+ *
+ * This function sets the value of the close flag of the specified window.
+ * This can be used to override the user's attempt to close the window, or
+ * to signal that it should be closed.
+ *
+ * @param[in] window The window whose flag to change.
+ * @param[in] value The new value.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @sa @ref window_close
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value);
+
+/*! @brief Sets the title of the specified window.
+ *
+ * This function sets the window title, encoded as UTF-8, of the specified
+ * window.
+ *
+ * @param[in] window The window whose title to change.
+ * @param[in] title The UTF-8 encoded window title.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @remark @osx The window title will not be updated until the next time you
+ * process events.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_title
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title);
+
+/*! @brief Sets the icon for the specified window.
+ *
+ * This function sets the icon of the specified window. If passed an array of
+ * candidate images, those of or closest to the sizes desired by the system are
+ * selected. If no images are specified, the window reverts to its default
+ * icon.
+ *
+ * The desired image sizes varies depending on platform and system settings.
+ * The selected images will be rescaled as needed. Good sizes include 16x16,
+ * 32x32 and 48x48.
+ *
+ * @param[in] window The window whose icon to set.
+ * @param[in] count The number of images in the specified array, or zero to
+ * revert to the default window icon.
+ * @param[in] images The images to create the icon from. This is ignored if
+ * count is zero.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @pointer_lifetime The specified image data is copied before this function
+ * returns.
+ *
+ * @remark @osx The GLFW window has no icon, as it is not a document
+ * window, so this function does nothing. The dock icon will be the same as
+ * the application bundle's icon. For more information on bundles, see the
+ * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
+ * in the Mac Developer Library.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_icon
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images);
+
+/*! @brief Retrieves the position of the client area of the specified window.
+ *
+ * This function retrieves the position, in screen coordinates, of the
+ * upper-left corner of the client area of the specified window.
+ *
+ * Any or all of the position arguments may be `NULL`. If an error occurs, all
+ * non-`NULL` position arguments will be set to zero.
+ *
+ * @param[in] window The window to query.
+ * @param[out] xpos Where to store the x-coordinate of the upper-left corner of
+ * the client area, or `NULL`.
+ * @param[out] ypos Where to store the y-coordinate of the upper-left corner of
+ * the client area, or `NULL`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_pos
+ * @sa glfwSetWindowPos
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos);
+
+/*! @brief Sets the position of the client area of the specified window.
+ *
+ * This function sets the position, in screen coordinates, of the upper-left
+ * corner of the client area of the specified windowed mode window. If the
+ * window is a full screen window, this function does nothing.
+ *
+ * __Do not use this function__ to move an already visible window unless you
+ * have very good reasons for doing so, as it will confuse and annoy the user.
+ *
+ * The window manager may put limits on what positions are allowed. GLFW
+ * cannot and should not override these limits.
+ *
+ * @param[in] window The window to query.
+ * @param[in] xpos The x-coordinate of the upper-left corner of the client area.
+ * @param[in] ypos The y-coordinate of the upper-left corner of the client area.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_pos
+ * @sa glfwGetWindowPos
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos);
+
+/*! @brief Retrieves the size of the client area of the specified window.
+ *
+ * This function retrieves the size, in screen coordinates, of the client area
+ * of the specified window. If you wish to retrieve the size of the
+ * framebuffer of the window in pixels, see @ref glfwGetFramebufferSize.
+ *
+ * Any or all of the size arguments may be `NULL`. If an error occurs, all
+ * non-`NULL` size arguments will be set to zero.
+ *
+ * @param[in] window The window whose size to retrieve.
+ * @param[out] width Where to store the width, in screen coordinates, of the
+ * client area, or `NULL`.
+ * @param[out] height Where to store the height, in screen coordinates, of the
+ * client area, or `NULL`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_size
+ * @sa glfwSetWindowSize
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height);
+
+/*! @brief Sets the size limits of the specified window.
+ *
+ * This function sets the size limits of the client area of the specified
+ * window. If the window is full screen, the size limits only take effect
+ * once it is made windowed. If the window is not resizable, this function
+ * does nothing.
+ *
+ * The size limits are applied immediately to a windowed mode window and may
+ * cause it to be resized.
+ *
+ * The maximum dimensions must be greater than or equal to the minimum
+ * dimensions and all must be greater than or equal to zero.
+ *
+ * @param[in] window The window to set limits for.
+ * @param[in] minwidth The minimum width, in screen coordinates, of the client
+ * area, or `GLFW_DONT_CARE`.
+ * @param[in] minheight The minimum height, in screen coordinates, of the
+ * client area, or `GLFW_DONT_CARE`.
+ * @param[in] maxwidth The maximum width, in screen coordinates, of the client
+ * area, or `GLFW_DONT_CARE`.
+ * @param[in] maxheight The maximum height, in screen coordinates, of the
+ * client area, or `GLFW_DONT_CARE`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @remark If you set size limits and an aspect ratio that conflict, the
+ * results are undefined.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_sizelimits
+ * @sa glfwSetWindowAspectRatio
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight);
+
+/*! @brief Sets the aspect ratio of the specified window.
+ *
+ * This function sets the required aspect ratio of the client area of the
+ * specified window. If the window is full screen, the aspect ratio only takes
+ * effect once it is made windowed. If the window is not resizable, this
+ * function does nothing.
+ *
+ * The aspect ratio is specified as a numerator and a denominator and both
+ * values must be greater than zero. For example, the common 16:9 aspect ratio
+ * is specified as 16 and 9, respectively.
+ *
+ * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect
+ * ratio limit is disabled.
+ *
+ * The aspect ratio is applied immediately to a windowed mode window and may
+ * cause it to be resized.
+ *
+ * @param[in] window The window to set limits for.
+ * @param[in] numer The numerator of the desired aspect ratio, or
+ * `GLFW_DONT_CARE`.
+ * @param[in] denom The denominator of the desired aspect ratio, or
+ * `GLFW_DONT_CARE`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @remark If you set size limits and an aspect ratio that conflict, the
+ * results are undefined.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_sizelimits
+ * @sa glfwSetWindowSizeLimits
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom);
+
+/*! @brief Sets the size of the client area of the specified window.
+ *
+ * This function sets the size, in screen coordinates, of the client area of
+ * the specified window.
+ *
+ * For full screen windows, this function updates the resolution of its desired
+ * video mode and switches to the video mode closest to it, without affecting
+ * the window's context. As the context is unaffected, the bit depths of the
+ * framebuffer remain unchanged.
+ *
+ * If you wish to update the refresh rate of the desired video mode in addition
+ * to its resolution, see @ref glfwSetWindowMonitor.
+ *
+ * The window manager may put limits on what sizes are allowed. GLFW cannot
+ * and should not override these limits.
+ *
+ * @param[in] window The window to resize.
+ * @param[in] width The desired width, in screen coordinates, of the window
+ * client area.
+ * @param[in] height The desired height, in screen coordinates, of the window
+ * client area.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_size
+ * @sa glfwGetWindowSize
+ * @sa glfwSetWindowMonitor
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height);
+
+/*! @brief Retrieves the size of the framebuffer of the specified window.
+ *
+ * This function retrieves the size, in pixels, of the framebuffer of the
+ * specified window. If you wish to retrieve the size of the window in screen
+ * coordinates, see @ref glfwGetWindowSize.
+ *
+ * Any or all of the size arguments may be `NULL`. If an error occurs, all
+ * non-`NULL` size arguments will be set to zero.
+ *
+ * @param[in] window The window whose framebuffer to query.
+ * @param[out] width Where to store the width, in pixels, of the framebuffer,
+ * or `NULL`.
+ * @param[out] height Where to store the height, in pixels, of the framebuffer,
+ * or `NULL`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_fbsize
+ * @sa glfwSetFramebufferSizeCallback
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height);
+
+/*! @brief Retrieves the size of the frame of the window.
+ *
+ * This function retrieves the size, in screen coordinates, of each edge of the
+ * frame of the specified window. This size includes the title bar, if the
+ * window has one. The size of the frame may vary depending on the
+ * [window-related hints](@ref window_hints_wnd) used to create it.
+ *
+ * Because this function retrieves the size of each window frame edge and not
+ * the offset along a particular coordinate axis, the retrieved values will
+ * always be zero or positive.
+ *
+ * Any or all of the size arguments may be `NULL`. If an error occurs, all
+ * non-`NULL` size arguments will be set to zero.
+ *
+ * @param[in] window The window whose frame size to query.
+ * @param[out] left Where to store the size, in screen coordinates, of the left
+ * edge of the window frame, or `NULL`.
+ * @param[out] top Where to store the size, in screen coordinates, of the top
+ * edge of the window frame, or `NULL`.
+ * @param[out] right Where to store the size, in screen coordinates, of the
+ * right edge of the window frame, or `NULL`.
+ * @param[out] bottom Where to store the size, in screen coordinates, of the
+ * bottom edge of the window frame, or `NULL`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_size
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom);
+
+/*! @brief Iconifies the specified window.
+ *
+ * This function iconifies (minimizes) the specified window if it was
+ * previously restored. If the window is already iconified, this function does
+ * nothing.
+ *
+ * If the specified window is a full screen window, the original monitor
+ * resolution is restored until the window is restored.
+ *
+ * @param[in] window The window to iconify.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_iconify
+ * @sa glfwRestoreWindow
+ * @sa glfwMaximizeWindow
+ *
+ * @since Added in version 2.1.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwIconifyWindow(GLFWwindow* window);
+
+/*! @brief Restores the specified window.
+ *
+ * This function restores the specified window if it was previously iconified
+ * (minimized) or maximized. If the window is already restored, this function
+ * does nothing.
+ *
+ * If the specified window is a full screen window, the resolution chosen for
+ * the window is restored on the selected monitor.
+ *
+ * @param[in] window The window to restore.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_iconify
+ * @sa glfwIconifyWindow
+ * @sa glfwMaximizeWindow
+ *
+ * @since Added in version 2.1.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwRestoreWindow(GLFWwindow* window);
+
+/*! @brief Maximizes the specified window.
+ *
+ * This function maximizes the specified window if it was previously not
+ * maximized. If the window is already maximized, this function does nothing.
+ *
+ * If the specified window is a full screen window, this function does nothing.
+ *
+ * @param[in] window The window to maximize.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @par Thread Safety
+ * This function may only be called from the main thread.
+ *
+ * @sa @ref window_iconify
+ * @sa glfwIconifyWindow
+ * @sa glfwRestoreWindow
+ *
+ * @since Added in GLFW 3.2.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwMaximizeWindow(GLFWwindow* window);
+
+/*! @brief Makes the specified window visible.
+ *
+ * This function makes the specified window visible if it was previously
+ * hidden. If the window is already visible or is in full screen mode, this
+ * function does nothing.
+ *
+ * @param[in] window The window to make visible.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_hide
+ * @sa glfwHideWindow
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwShowWindow(GLFWwindow* window);
+
+/*! @brief Hides the specified window.
+ *
+ * This function hides the specified window if it was previously visible. If
+ * the window is already hidden or is in full screen mode, this function does
+ * nothing.
+ *
+ * @param[in] window The window to hide.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_hide
+ * @sa glfwShowWindow
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwHideWindow(GLFWwindow* window);
+
+/*! @brief Brings the specified window to front and sets input focus.
+ *
+ * This function brings the specified window to front and sets input focus.
+ * The window should already be visible and not iconified.
+ *
+ * By default, both windowed and full screen mode windows are focused when
+ * initially created. Set the [GLFW_FOCUSED](@ref window_hints_wnd) to disable
+ * this behavior.
+ *
+ * __Do not use this function__ to steal focus from other applications unless
+ * you are certain that is what the user wants. Focus stealing can be
+ * extremely disruptive.
+ *
+ * @param[in] window The window to give input focus.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_focus
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwFocusWindow(GLFWwindow* window);
+
+/*! @brief Returns the monitor that the window uses for full screen mode.
+ *
+ * This function returns the handle of the monitor that the specified window is
+ * in full screen on.
+ *
+ * @param[in] window The window to query.
+ * @return The monitor, or `NULL` if the window is in windowed mode or an error
+ * occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_monitor
+ * @sa glfwSetWindowMonitor
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window);
+
+/*! @brief Sets the mode, monitor, video mode and placement of a window.
+ *
+ * This function sets the monitor that the window uses for full screen mode or,
+ * if the monitor is `NULL`, makes it windowed mode.
+ *
+ * When setting a monitor, this function updates the width, height and refresh
+ * rate of the desired video mode and switches to the video mode closest to it.
+ * The window position is ignored when setting a monitor.
+ *
+ * When the monitor is `NULL`, the position, width and height are used to
+ * place the window client area. The refresh rate is ignored when no monitor
+ * is specified.
+ *
+ * If you only wish to update the resolution of a full screen window or the
+ * size of a windowed mode window, see @ref glfwSetWindowSize.
+ *
+ * When a window transitions from full screen to windowed mode, this function
+ * restores any previous window settings such as whether it is decorated,
+ * floating, resizable, has size or aspect ratio limits, etc..
+ *
+ * @param[in] window The window whose monitor, size or video mode to set.
+ * @param[in] monitor The desired monitor, or `NULL` to set windowed mode.
+ * @param[in] xpos The desired x-coordinate of the upper-left corner of the
+ * client area.
+ * @param[in] ypos The desired y-coordinate of the upper-left corner of the
+ * client area.
+ * @param[in] width The desired with, in screen coordinates, of the client area
+ * or video mode.
+ * @param[in] height The desired height, in screen coordinates, of the client
+ * area or video mode.
+ * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode,
+ * or `GLFW_DONT_CARE`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_monitor
+ * @sa @ref window_full_screen
+ * @sa glfwGetWindowMonitor
+ * @sa glfwSetWindowSize
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate);
+
+/*! @brief Returns an attribute of the specified window.
+ *
+ * This function returns the value of an attribute of the specified window or
+ * its OpenGL or OpenGL ES context.
+ *
+ * @param[in] window The window to query.
+ * @param[in] attrib The [window attribute](@ref window_attribs) whose value to
+ * return.
+ * @return The value of the attribute, or zero if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @remark Framebuffer related hints are not window attributes. See @ref
+ * window_attribs_fb for more information.
+ *
+ * @remark Zero is a valid value for many window and context related
+ * attributes so you cannot use a return value of zero as an indication of
+ * errors. However, this function should not fail as long as it is passed
+ * valid arguments and the library has been [initialized](@ref intro_init).
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_attribs
+ *
+ * @since Added in version 3.0. Replaces `glfwGetWindowParam` and
+ * `glfwGetGLVersion`.
+ *
+ * @ingroup window
+ */
+GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib);
+
+/*! @brief Sets the user pointer of the specified window.
+ *
+ * This function sets the user-defined pointer of the specified window. The
+ * current value is retained until the window is destroyed. The initial value
+ * is `NULL`.
+ *
+ * @param[in] window The window whose pointer to set.
+ * @param[in] pointer The new value.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @sa @ref window_userptr
+ * @sa glfwGetWindowUserPointer
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer);
+
+/*! @brief Returns the user pointer of the specified window.
+ *
+ * This function returns the current value of the user-defined pointer of the
+ * specified window. The initial value is `NULL`.
+ *
+ * @param[in] window The window whose pointer to return.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @sa @ref window_userptr
+ * @sa glfwSetWindowUserPointer
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window);
+
+/*! @brief Sets the position callback for the specified window.
+ *
+ * This function sets the position callback of the specified window, which is
+ * called when the window is moved. The callback is provided with the screen
+ * position of the upper-left corner of the client area of the window.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_pos
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun cbfun);
+
+/*! @brief Sets the size callback for the specified window.
+ *
+ * This function sets the size callback of the specified window, which is
+ * called when the window is resized. The callback is provided with the size,
+ * in screen coordinates, of the client area of the window.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_size
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle parameter and return value.
+ *
+ * @ingroup window
+ */
+GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun cbfun);
+
+/*! @brief Sets the close callback for the specified window.
+ *
+ * This function sets the close callback of the specified window, which is
+ * called when the user attempts to close the window, for example by clicking
+ * the close widget in the title bar.
+ *
+ * The close flag is set before this callback is called, but you can modify it
+ * at any time with @ref glfwSetWindowShouldClose.
+ *
+ * The close callback is not triggered by @ref glfwDestroyWindow.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @remark @osx Selecting Quit from the application menu will trigger the close
+ * callback for all windows.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_close
+ *
+ * @since Added in version 2.5.
+ * @glfw3 Added window handle parameter and return value.
+ *
+ * @ingroup window
+ */
+GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun cbfun);
+
+/*! @brief Sets the refresh callback for the specified window.
+ *
+ * This function sets the refresh callback of the specified window, which is
+ * called when the client area of the window needs to be redrawn, for example
+ * if the window has been exposed after having been covered by another window.
+ *
+ * On compositing window systems such as Aero, Compiz or Aqua, where the window
+ * contents are saved off-screen, this callback may be called only very
+ * infrequently or never at all.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_refresh
+ *
+ * @since Added in version 2.5.
+ * @glfw3 Added window handle parameter and return value.
+ *
+ * @ingroup window
+ */
+GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun cbfun);
+
+/*! @brief Sets the focus callback for the specified window.
+ *
+ * This function sets the focus callback of the specified window, which is
+ * called when the window gains or loses input focus.
+ *
+ * After the focus callback is called for a window that lost input focus,
+ * synthetic key and mouse button release events will be generated for all such
+ * that had been pressed. For more information, see @ref glfwSetKeyCallback
+ * and @ref glfwSetMouseButtonCallback.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_focus
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun cbfun);
+
+/*! @brief Sets the iconify callback for the specified window.
+ *
+ * This function sets the iconification callback of the specified window, which
+ * is called when the window is iconified or restored.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_iconify
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun cbfun);
+
+/*! @brief Sets the framebuffer resize callback for the specified window.
+ *
+ * This function sets the framebuffer resize callback of the specified window,
+ * which is called when the framebuffer of the specified window is resized.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref window_fbsize
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun);
+
+/*! @brief Processes all pending events.
+ *
+ * This function processes only those events that are already in the event
+ * queue and then returns immediately. Processing events will cause the window
+ * and input callbacks associated with those events to be called.
+ *
+ * On some platforms, a window move, resize or menu operation will cause event
+ * processing to block. This is due to how event processing is designed on
+ * those platforms. You can use the
+ * [window refresh callback](@ref window_refresh) to redraw the contents of
+ * your window when necessary during such operations.
+ *
+ * On some platforms, certain events are sent directly to the application
+ * without going through the event queue, causing callbacks to be called
+ * outside of a call to one of the event processing functions.
+ *
+ * Event processing is not required for joystick input to work.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @reentrancy This function must not be called from a callback.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref events
+ * @sa glfwWaitEvents
+ * @sa glfwWaitEventsTimeout
+ *
+ * @since Added in version 1.0.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwPollEvents(void);
+
+/*! @brief Waits until events are queued and processes them.
+ *
+ * This function puts the calling thread to sleep until at least one event is
+ * available in the event queue. Once one or more events are available,
+ * it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue
+ * are processed and the function then returns immediately. Processing events
+ * will cause the window and input callbacks associated with those events to be
+ * called.
+ *
+ * Since not all events are associated with callbacks, this function may return
+ * without a callback having been called even if you are monitoring all
+ * callbacks.
+ *
+ * On some platforms, a window move, resize or menu operation will cause event
+ * processing to block. This is due to how event processing is designed on
+ * those platforms. You can use the
+ * [window refresh callback](@ref window_refresh) to redraw the contents of
+ * your window when necessary during such operations.
+ *
+ * On some platforms, certain callbacks may be called outside of a call to one
+ * of the event processing functions.
+ *
+ * If no windows exist, this function returns immediately. For synchronization
+ * of threads in applications that do not create windows, use your threading
+ * library of choice.
+ *
+ * Event processing is not required for joystick input to work.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @reentrancy This function must not be called from a callback.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref events
+ * @sa glfwPollEvents
+ * @sa glfwWaitEventsTimeout
+ *
+ * @since Added in version 2.5.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwWaitEvents(void);
+
+/*! @brief Waits with timeout until events are queued and processes them.
+ *
+ * This function puts the calling thread to sleep until at least one event is
+ * available in the event queue, or until the specified timeout is reached. If
+ * one or more events are available, it behaves exactly like @ref
+ * glfwPollEvents, i.e. the events in the queue are processed and the function
+ * then returns immediately. Processing events will cause the window and input
+ * callbacks associated with those events to be called.
+ *
+ * The timeout value must be a positive finite number.
+ *
+ * Since not all events are associated with callbacks, this function may return
+ * without a callback having been called even if you are monitoring all
+ * callbacks.
+ *
+ * On some platforms, a window move, resize or menu operation will cause event
+ * processing to block. This is due to how event processing is designed on
+ * those platforms. You can use the
+ * [window refresh callback](@ref window_refresh) to redraw the contents of
+ * your window when necessary during such operations.
+ *
+ * On some platforms, certain callbacks may be called outside of a call to one
+ * of the event processing functions.
+ *
+ * If no windows exist, this function returns immediately. For synchronization
+ * of threads in applications that do not create windows, use your threading
+ * library of choice.
+ *
+ * Event processing is not required for joystick input to work.
+ *
+ * @param[in] timeout The maximum amount of time, in seconds, to wait.
+ *
+ * @reentrancy This function must not be called from a callback.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref events
+ * @sa glfwPollEvents
+ * @sa glfwWaitEvents
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwWaitEventsTimeout(double timeout);
+
+/*! @brief Posts an empty event to the event queue.
+ *
+ * This function posts an empty event from the current thread to the event
+ * queue, causing @ref glfwWaitEvents to return.
+ *
+ * If no windows exist, this function returns immediately. For synchronization
+ * of threads in applications that do not create windows, use your threading
+ * library of choice.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref events
+ * @sa glfwWaitEvents
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwPostEmptyEvent(void);
+
+/*! @brief Returns the value of an input option for the specified window.
+ *
+ * This function returns the value of an input option for the specified window.
+ * The mode must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
+ * `GLFW_STICKY_MOUSE_BUTTONS`.
+ *
+ * @param[in] window The window to query.
+ * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
+ * `GLFW_STICKY_MOUSE_BUTTONS`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_INVALID_ENUM.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa glfwSetInputMode
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup input
+ */
+GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
+
+/*! @brief Sets an input option for the specified window.
+ *
+ * This function sets an input mode option for the specified window. The mode
+ * must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
+ * `GLFW_STICKY_MOUSE_BUTTONS`.
+ *
+ * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor
+ * modes:
+ * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally.
+ * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client
+ * area of the window but does not restrict the cursor from leaving.
+ * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual
+ * and unlimited cursor movement. This is useful for implementing for
+ * example 3D camera controls.
+ *
+ * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to
+ * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are
+ * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS`
+ * the next time it is called even if the key had been released before the
+ * call. This is useful when you are only interested in whether keys have been
+ * pressed but not when or in which order.
+ *
+ * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either
+ * `GLFW_TRUE` to enable sticky mouse buttons, or `GLFW_FALSE` to disable it.
+ * If sticky mouse buttons are enabled, a mouse button press will ensure that
+ * @ref glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even
+ * if the mouse button had been released before the call. This is useful when
+ * you are only interested in whether mouse buttons have been pressed but not
+ * when or in which order.
+ *
+ * @param[in] window The window whose input mode to set.
+ * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
+ * `GLFW_STICKY_MOUSE_BUTTONS`.
+ * @param[in] value The new value of the specified input mode.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa glfwGetInputMode
+ *
+ * @since Added in version 3.0. Replaces `glfwEnable` and `glfwDisable`.
+ *
+ * @ingroup input
+ */
+GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value);
+
+/*! @brief Returns the localized name of the specified printable key.
+ *
+ * This function returns the localized name of the specified printable key.
+ * This is intended for displaying key bindings to the user.
+ *
+ * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used instead, otherwise
+ * the scancode is ignored. If a non-printable key or (if the key is
+ * `GLFW_KEY_UNKNOWN`) a scancode that maps to a non-printable key is
+ * specified, this function returns `NULL`.
+ *
+ * This behavior allows you to pass in the arguments passed to the
+ * [key callback](@ref input_key) without modification.
+ *
+ * The printable keys are:
+ * - `GLFW_KEY_APOSTROPHE`
+ * - `GLFW_KEY_COMMA`
+ * - `GLFW_KEY_MINUS`
+ * - `GLFW_KEY_PERIOD`
+ * - `GLFW_KEY_SLASH`
+ * - `GLFW_KEY_SEMICOLON`
+ * - `GLFW_KEY_EQUAL`
+ * - `GLFW_KEY_LEFT_BRACKET`
+ * - `GLFW_KEY_RIGHT_BRACKET`
+ * - `GLFW_KEY_BACKSLASH`
+ * - `GLFW_KEY_WORLD_1`
+ * - `GLFW_KEY_WORLD_2`
+ * - `GLFW_KEY_0` to `GLFW_KEY_9`
+ * - `GLFW_KEY_A` to `GLFW_KEY_Z`
+ * - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9`
+ * - `GLFW_KEY_KP_DECIMAL`
+ * - `GLFW_KEY_KP_DIVIDE`
+ * - `GLFW_KEY_KP_MULTIPLY`
+ * - `GLFW_KEY_KP_SUBTRACT`
+ * - `GLFW_KEY_KP_ADD`
+ * - `GLFW_KEY_KP_EQUAL`
+ *
+ * @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`.
+ * @param[in] scancode The scancode of the key to query.
+ * @return The localized name of the key, or `NULL`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @pointer_lifetime The returned string is allocated and freed by GLFW. You
+ * should not free it yourself. It is valid until the next call to @ref
+ * glfwGetKeyName, or until the library is terminated.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref input_key_name
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup input
+ */
+GLFWAPI const char* glfwGetKeyName(int key, int scancode);
+
+/*! @brief Returns the last reported state of a keyboard key for the specified
+ * window.
+ *
+ * This function returns the last state reported for the specified key to the
+ * specified window. The returned state is one of `GLFW_PRESS` or
+ * `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to
+ * the key callback.
+ *
+ * If the `GLFW_STICKY_KEYS` input mode is enabled, this function returns
+ * `GLFW_PRESS` the first time you call it for a key that was pressed, even if
+ * that key has already been released.
+ *
+ * The key functions deal with physical keys, with [key tokens](@ref keys)
+ * named after their use on the standard US keyboard layout. If you want to
+ * input text, use the Unicode character callback instead.
+ *
+ * The [modifier key bit masks](@ref mods) are not key tokens and cannot be
+ * used with this function.
+ *
+ * __Do not use this function__ to implement [text input](@ref input_char).
+ *
+ * @param[in] window The desired window.
+ * @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is
+ * not a valid key for this function.
+ * @return One of `GLFW_PRESS` or `GLFW_RELEASE`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_INVALID_ENUM.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref input_key
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup input
+ */
+GLFWAPI int glfwGetKey(GLFWwindow* window, int key);
+
+/*! @brief Returns the last reported state of a mouse button for the specified
+ * window.
+ *
+ * This function returns the last state reported for the specified mouse button
+ * to the specified window. The returned state is one of `GLFW_PRESS` or
+ * `GLFW_RELEASE`.
+ *
+ * If the `GLFW_STICKY_MOUSE_BUTTONS` input mode is enabled, this function
+ * `GLFW_PRESS` the first time you call it for a mouse button that was pressed,
+ * even if that mouse button has already been released.
+ *
+ * @param[in] window The desired window.
+ * @param[in] button The desired [mouse button](@ref buttons).
+ * @return One of `GLFW_PRESS` or `GLFW_RELEASE`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_INVALID_ENUM.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref input_mouse_button
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup input
+ */
+GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button);
+
+/*! @brief Retrieves the position of the cursor relative to the client area of
+ * the window.
+ *
+ * This function returns the position of the cursor, in screen coordinates,
+ * relative to the upper-left corner of the client area of the specified
+ * window.
+ *
+ * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor
+ * position is unbounded and limited only by the minimum and maximum values of
+ * a `double`.
+ *
+ * The coordinate can be converted to their integer equivalents with the
+ * `floor` function. Casting directly to an integer type works for positive
+ * coordinates, but fails for negative ones.
+ *
+ * Any or all of the position arguments may be `NULL`. If an error occurs, all
+ * non-`NULL` position arguments will be set to zero.
+ *
+ * @param[in] window The desired window.
+ * @param[out] xpos Where to store the cursor x-coordinate, relative to the
+ * left edge of the client area, or `NULL`.
+ * @param[out] ypos Where to store the cursor y-coordinate, relative to the to
+ * top edge of the client area, or `NULL`.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref cursor_pos
+ * @sa glfwSetCursorPos
+ *
+ * @since Added in version 3.0. Replaces `glfwGetMousePos`.
+ *
+ * @ingroup input
+ */
+GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos);
+
+/*! @brief Sets the position of the cursor, relative to the client area of the
+ * window.
+ *
+ * This function sets the position, in screen coordinates, of the cursor
+ * relative to the upper-left corner of the client area of the specified
+ * window. The window must have input focus. If the window does not have
+ * input focus when this function is called, it fails silently.
+ *
+ * __Do not use this function__ to implement things like camera controls. GLFW
+ * already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the
+ * cursor, transparently re-centers it and provides unconstrained cursor
+ * motion. See @ref glfwSetInputMode for more information.
+ *
+ * If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is
+ * unconstrained and limited only by the minimum and maximum values of
+ * a `double`.
+ *
+ * @param[in] window The desired window.
+ * @param[in] xpos The desired x-coordinate, relative to the left edge of the
+ * client area.
+ * @param[in] ypos The desired y-coordinate, relative to the top edge of the
+ * client area.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref cursor_pos
+ * @sa glfwGetCursorPos
+ *
+ * @since Added in version 3.0. Replaces `glfwSetMousePos`.
+ *
+ * @ingroup input
+ */
+GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos);
+
+/*! @brief Creates a custom cursor.
+ *
+ * Creates a new custom cursor image that can be set for a window with @ref
+ * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor.
+ * Any remaining cursors are destroyed by @ref glfwTerminate.
+ *
+ * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight
+ * bits per channel. They are arranged canonically as packed sequential rows,
+ * starting from the top-left corner.
+ *
+ * The cursor hotspot is specified in pixels, relative to the upper-left corner
+ * of the cursor image. Like all other coordinate systems in GLFW, the X-axis
+ * points to the right and the Y-axis points down.
+ *
+ * @param[in] image The desired cursor image.
+ * @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot.
+ * @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot.
+ * @return The handle of the created cursor, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @pointer_lifetime The specified image data is copied before this function
+ * returns.
+ *
+ * @reentrancy This function must not be called from a callback.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref cursor_object
+ * @sa glfwDestroyCursor
+ * @sa glfwCreateStandardCursor
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup input
+ */
+GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot);
+
+/*! @brief Creates a cursor with a standard shape.
+ *
+ * Returns a cursor with a [standard shape](@ref shapes), that can be set for
+ * a window with @ref glfwSetCursor.
+ *
+ * @param[in] shape One of the [standard shapes](@ref shapes).
+ * @return A new cursor ready to use or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @reentrancy This function must not be called from a callback.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref cursor_object
+ * @sa glfwCreateCursor
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup input
+ */
+GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape);
+
+/*! @brief Destroys a cursor.
+ *
+ * This function destroys a cursor previously created with @ref
+ * glfwCreateCursor. Any remaining cursors will be destroyed by @ref
+ * glfwTerminate.
+ *
+ * @param[in] cursor The cursor object to destroy.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @reentrancy This function must not be called from a callback.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref cursor_object
+ * @sa glfwCreateCursor
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup input
+ */
+GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor);
+
+/*! @brief Sets the cursor for the window.
+ *
+ * This function sets the cursor image to be used when the cursor is over the
+ * client area of the specified window. The set cursor will only be visible
+ * when the [cursor mode](@ref cursor_mode) of the window is
+ * `GLFW_CURSOR_NORMAL`.
+ *
+ * On some platforms, the set cursor may not be visible unless the window also
+ * has input focus.
+ *
+ * @param[in] window The window to set the cursor for.
+ * @param[in] cursor The cursor to set, or `NULL` to switch back to the default
+ * arrow cursor.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref cursor_object
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup input
+ */
+GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor);
+
+/*! @brief Sets the key callback.
+ *
+ * This function sets the key callback of the specified window, which is called
+ * when a key is pressed, repeated or released.
+ *
+ * The key functions deal with physical keys, with layout independent
+ * [key tokens](@ref keys) named after their values in the standard US keyboard
+ * layout. If you want to input text, use the
+ * [character callback](@ref glfwSetCharCallback) instead.
+ *
+ * When a window loses input focus, it will generate synthetic key release
+ * events for all pressed keys. You can tell these events from user-generated
+ * events by the fact that the synthetic ones are generated after the focus
+ * loss event has been processed, i.e. after the
+ * [window focus callback](@ref glfwSetWindowFocusCallback) has been called.
+ *
+ * The scancode of a key is specific to that platform or sometimes even to that
+ * machine. Scancodes are intended to allow users to bind keys that don't have
+ * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their
+ * state is not saved and so it cannot be queried with @ref glfwGetKey.
+ *
+ * Sometimes GLFW needs to generate synthetic key events, in which case the
+ * scancode may be zero.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new key callback, or `NULL` to remove the currently
+ * set callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref input_key
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle parameter and return value.
+ *
+ * @ingroup input
+ */
+GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun);
+
+/*! @brief Sets the Unicode character callback.
+ *
+ * This function sets the character callback of the specified window, which is
+ * called when a Unicode character is input.
+ *
+ * The character callback is intended for Unicode text input. As it deals with
+ * characters, it is keyboard layout dependent, whereas the
+ * [key callback](@ref glfwSetKeyCallback) is not. Characters do not map 1:1
+ * to physical keys, as a key may produce zero, one or more characters. If you
+ * want to know whether a specific physical key was pressed or released, see
+ * the key callback instead.
+ *
+ * The character callback behaves as system text input normally does and will
+ * not be called if modifier keys are held down that would prevent normal text
+ * input on that platform, for example a Super (Command) key on OS X or Alt key
+ * on Windows. There is a
+ * [character with modifiers callback](@ref glfwSetCharModsCallback) that
+ * receives these events.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref input_char
+ *
+ * @since Added in version 2.4.
+ * @glfw3 Added window handle parameter and return value.
+ *
+ * @ingroup input
+ */
+GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun);
+
+/*! @brief Sets the Unicode character with modifiers callback.
+ *
+ * This function sets the character with modifiers callback of the specified
+ * window, which is called when a Unicode character is input regardless of what
+ * modifier keys are used.
+ *
+ * The character with modifiers callback is intended for implementing custom
+ * Unicode character input. For regular Unicode text input, see the
+ * [character callback](@ref glfwSetCharCallback). Like the character
+ * callback, the character with modifiers callback deals with characters and is
+ * keyboard layout dependent. Characters do not map 1:1 to physical keys, as
+ * a key may produce zero, one or more characters. If you want to know whether
+ * a specific physical key was pressed or released, see the
+ * [key callback](@ref glfwSetKeyCallback) instead.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or an
+ * error occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref input_char
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup input
+ */
+GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun);
+
+/*! @brief Sets the mouse button callback.
+ *
+ * This function sets the mouse button callback of the specified window, which
+ * is called when a mouse button is pressed or released.
+ *
+ * When a window loses input focus, it will generate synthetic mouse button
+ * release events for all pressed mouse buttons. You can tell these events
+ * from user-generated events by the fact that the synthetic ones are generated
+ * after the focus loss event has been processed, i.e. after the
+ * [window focus callback](@ref glfwSetWindowFocusCallback) has been called.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref input_mouse_button
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle parameter and return value.
+ *
+ * @ingroup input
+ */
+GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun cbfun);
+
+/*! @brief Sets the cursor position callback.
+ *
+ * This function sets the cursor position callback of the specified window,
+ * which is called when the cursor is moved. The callback is provided with the
+ * position, in screen coordinates, relative to the upper-left corner of the
+ * client area of the window.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref cursor_pos
+ *
+ * @since Added in version 3.0. Replaces `glfwSetMousePosCallback`.
+ *
+ * @ingroup input
+ */
+GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun cbfun);
+
+/*! @brief Sets the cursor enter/exit callback.
+ *
+ * This function sets the cursor boundary crossing callback of the specified
+ * window, which is called when the cursor enters or leaves the client area of
+ * the window.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref cursor_enter
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup input
+ */
+GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun cbfun);
+
+/*! @brief Sets the scroll callback.
+ *
+ * This function sets the scroll callback of the specified window, which is
+ * called when a scrolling device is used, such as a mouse wheel or scrolling
+ * area of a touchpad.
+ *
+ * The scroll callback receives all scrolling input, like that from a mouse
+ * wheel or a touchpad scrolling area.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new scroll callback, or `NULL` to remove the currently
+ * set callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref scrolling
+ *
+ * @since Added in version 3.0. Replaces `glfwSetMouseWheelCallback`.
+ *
+ * @ingroup input
+ */
+GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun);
+
+/*! @brief Sets the file drop callback.
+ *
+ * This function sets the file drop callback of the specified window, which is
+ * called when one or more dragged files are dropped on the window.
+ *
+ * Because the path array and its strings may have been generated specifically
+ * for that event, they are not guaranteed to be valid after the callback has
+ * returned. If you wish to use them after the callback returns, you need to
+ * make a deep copy.
+ *
+ * @param[in] window The window whose callback to set.
+ * @param[in] cbfun The new file drop callback, or `NULL` to remove the
+ * currently set callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref path_drop
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup input
+ */
+GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun);
+
+/*! @brief Returns whether the specified joystick is present.
+ *
+ * This function returns whether the specified joystick is present.
+ *
+ * @param[in] joy The [joystick](@ref joysticks) to query.
+ * @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref joystick
+ *
+ * @since Added in version 3.0. Replaces `glfwGetJoystickParam`.
+ *
+ * @ingroup input
+ */
+GLFWAPI int glfwJoystickPresent(int joy);
+
+/*! @brief Returns the values of all axes of the specified joystick.
+ *
+ * This function returns the values of all axes of the specified joystick.
+ * Each element in the array is a value between -1.0 and 1.0.
+ *
+ * Querying a joystick slot with no device present is not an error, but will
+ * cause this function to return `NULL`. Call @ref glfwJoystickPresent to
+ * check device presence.
+ *
+ * @param[in] joy The [joystick](@ref joysticks) to query.
+ * @param[out] count Where to store the number of axis values in the returned
+ * array. This is set to zero if an error occurred.
+ * @return An array of axis values, or `NULL` if the joystick is not present.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @pointer_lifetime The returned array is allocated and freed by GLFW. You
+ * should not free it yourself. It is valid until the specified joystick is
+ * disconnected, this function is called again for that joystick or the library
+ * is terminated.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref joystick_axis
+ *
+ * @since Added in version 3.0. Replaces `glfwGetJoystickPos`.
+ *
+ * @ingroup input
+ */
+GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count);
+
+/*! @brief Returns the state of all buttons of the specified joystick.
+ *
+ * This function returns the state of all buttons of the specified joystick.
+ * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`.
+ *
+ * Querying a joystick slot with no device present is not an error, but will
+ * cause this function to return `NULL`. Call @ref glfwJoystickPresent to
+ * check device presence.
+ *
+ * @param[in] joy The [joystick](@ref joysticks) to query.
+ * @param[out] count Where to store the number of button states in the returned
+ * array. This is set to zero if an error occurred.
+ * @return An array of button states, or `NULL` if the joystick is not present.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @pointer_lifetime The returned array is allocated and freed by GLFW. You
+ * should not free it yourself. It is valid until the specified joystick is
+ * disconnected, this function is called again for that joystick or the library
+ * is terminated.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref joystick_button
+ *
+ * @since Added in version 2.2.
+ * @glfw3 Changed to return a dynamic array.
+ *
+ * @ingroup input
+ */
+GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count);
+
+/*! @brief Returns the name of the specified joystick.
+ *
+ * This function returns the name, encoded as UTF-8, of the specified joystick.
+ * The returned string is allocated and freed by GLFW. You should not free it
+ * yourself.
+ *
+ * Querying a joystick slot with no device present is not an error, but will
+ * cause this function to return `NULL`. Call @ref glfwJoystickPresent to
+ * check device presence.
+ *
+ * @param[in] joy The [joystick](@ref joysticks) to query.
+ * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick
+ * is not present.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @pointer_lifetime The returned string is allocated and freed by GLFW. You
+ * should not free it yourself. It is valid until the specified joystick is
+ * disconnected, this function is called again for that joystick or the library
+ * is terminated.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref joystick_name
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup input
+ */
+GLFWAPI const char* glfwGetJoystickName(int joy);
+
+/*! @brief Sets the joystick configuration callback.
+ *
+ * This function sets the joystick configuration callback, or removes the
+ * currently set callback. This is called when a joystick is connected to or
+ * disconnected from the system.
+ *
+ * @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ * callback.
+ * @return The previously set callback, or `NULL` if no callback was set or the
+ * library had not been [initialized](@ref intro_init).
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref joystick_event
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup input
+ */
+GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun);
+
+/*! @brief Sets the clipboard to the specified string.
+ *
+ * This function sets the system clipboard to the specified, UTF-8 encoded
+ * string.
+ *
+ * @param[in] window The window that will own the clipboard contents.
+ * @param[in] string A UTF-8 encoded string.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @pointer_lifetime The specified string is copied before this function
+ * returns.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref clipboard
+ * @sa glfwGetClipboardString
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup input
+ */
+GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string);
+
+/*! @brief Returns the contents of the clipboard as a string.
+ *
+ * This function returns the contents of the system clipboard, if it contains
+ * or is convertible to a UTF-8 encoded string. If the clipboard is empty or
+ * if its contents cannot be converted, `NULL` is returned and a @ref
+ * GLFW_FORMAT_UNAVAILABLE error is generated.
+ *
+ * @param[in] window The window that will request the clipboard contents.
+ * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL`
+ * if an [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @pointer_lifetime The returned string is allocated and freed by GLFW. You
+ * should not free it yourself. It is valid until the next call to @ref
+ * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library
+ * is terminated.
+ *
+ * @thread_safety This function must only be called from the main thread.
+ *
+ * @sa @ref clipboard
+ * @sa glfwSetClipboardString
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup input
+ */
+GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window);
+
+/*! @brief Returns the value of the GLFW timer.
+ *
+ * This function returns the value of the GLFW timer. Unless the timer has
+ * been set using @ref glfwSetTime, the timer measures time elapsed since GLFW
+ * was initialized.
+ *
+ * The resolution of the timer is system dependent, but is usually on the order
+ * of a few micro- or nanoseconds. It uses the highest-resolution monotonic
+ * time source on each supported platform.
+ *
+ * @return The current value, in seconds, or zero if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function may be called from any thread. Reading and
+ * writing of the internal timer offset is not atomic, so it needs to be
+ * externally synchronized with calls to @ref glfwSetTime.
+ *
+ * @sa @ref time
+ *
+ * @since Added in version 1.0.
+ *
+ * @ingroup input
+ */
+GLFWAPI double glfwGetTime(void);
+
+/*! @brief Sets the GLFW timer.
+ *
+ * This function sets the value of the GLFW timer. It then continues to count
+ * up from that value. The value must be a positive finite number less than
+ * or equal to 18446744073.0, which is approximately 584.5 years.
+ *
+ * @param[in] time The new value, in seconds.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_INVALID_VALUE.
+ *
+ * @remark The upper limit of the timer is calculated as
+ * floor((2<sup>64</sup> - 1) / 10<sup>9</sup>) and is due to implementations
+ * storing nanoseconds in 64 bits. The limit may be increased in the future.
+ *
+ * @thread_safety This function may be called from any thread. Reading and
+ * writing of the internal timer offset is not atomic, so it needs to be
+ * externally synchronized with calls to @ref glfwGetTime.
+ *
+ * @sa @ref time
+ *
+ * @since Added in version 2.2.
+ *
+ * @ingroup input
+ */
+GLFWAPI void glfwSetTime(double time);
+
+/*! @brief Returns the current value of the raw timer.
+ *
+ * This function returns the current value of the raw timer, measured in
+ * 1&nbsp;/&nbsp;frequency seconds. To get the frequency, call @ref
+ * glfwGetTimerFrequency.
+ *
+ * @return The value of the timer, or zero if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref time
+ * @sa glfwGetTimerFrequency
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup input
+ */
+GLFWAPI uint64_t glfwGetTimerValue(void);
+
+/*! @brief Returns the frequency, in Hz, of the raw timer.
+ *
+ * This function returns the frequency, in Hz, of the raw timer.
+ *
+ * @return The frequency of the timer, in Hz, or zero if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref time
+ * @sa glfwGetTimerValue
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup input
+ */
+GLFWAPI uint64_t glfwGetTimerFrequency(void);
+
+/*! @brief Makes the context of the specified window current for the calling
+ * thread.
+ *
+ * This function makes the OpenGL or OpenGL ES context of the specified window
+ * current on the calling thread. A context can only be made current on
+ * a single thread at a time and each thread can have only a single current
+ * context at a time.
+ *
+ * By default, making a context non-current implicitly forces a pipeline flush.
+ * On machines that support `GL_KHR_context_flush_control`, you can control
+ * whether a context performs this flush by setting the
+ * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref window_hints_ctx) window hint.
+ *
+ * The specified window must have an OpenGL or OpenGL ES context. Specifying
+ * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT
+ * error.
+ *
+ * @param[in] window The window whose context to make current, or `NULL` to
+ * detach the current context.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref context_current
+ * @sa glfwGetCurrentContext
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup context
+ */
+GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window);
+
+/*! @brief Returns the window whose context is current on the calling thread.
+ *
+ * This function returns the window whose OpenGL or OpenGL ES context is
+ * current on the calling thread.
+ *
+ * @return The window whose context is current, or `NULL` if no window's
+ * context is current.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref context_current
+ * @sa glfwMakeContextCurrent
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup context
+ */
+GLFWAPI GLFWwindow* glfwGetCurrentContext(void);
+
+/*! @brief Swaps the front and back buffers of the specified window.
+ *
+ * This function swaps the front and back buffers of the specified window when
+ * rendering with OpenGL or OpenGL ES. If the swap interval is greater than
+ * zero, the GPU driver waits the specified number of screen updates before
+ * swapping the buffers.
+ *
+ * The specified window must have an OpenGL or OpenGL ES context. Specifying
+ * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT
+ * error.
+ *
+ * This function does not apply to Vulkan. If you are rendering with Vulkan,
+ * see `vkQueuePresentKHR` instead.
+ *
+ * @param[in] window The window whose buffers to swap.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @remark __EGL:__ The context of the specified window must be current on the
+ * calling thread.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref buffer_swap
+ * @sa glfwSwapInterval
+ *
+ * @since Added in version 1.0.
+ * @glfw3 Added window handle parameter.
+ *
+ * @ingroup window
+ */
+GLFWAPI void glfwSwapBuffers(GLFWwindow* window);
+
+/*! @brief Sets the swap interval for the current context.
+ *
+ * This function sets the swap interval for the current OpenGL or OpenGL ES
+ * context, i.e. the number of screen updates to wait from the time @ref
+ * glfwSwapBuffers was called before swapping the buffers and returning. This
+ * is sometimes called _vertical synchronization_, _vertical retrace
+ * synchronization_ or just _vsync_.
+ *
+ * Contexts that support either of the `WGL_EXT_swap_control_tear` and
+ * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals,
+ * which allow the driver to swap even if a frame arrives a little bit late.
+ * You can check for the presence of these extensions using @ref
+ * glfwExtensionSupported. For more information about swap tearing, see the
+ * extension specifications.
+ *
+ * A context must be current on the calling thread. Calling this function
+ * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error.
+ *
+ * This function does not apply to Vulkan. If you are rendering with Vulkan,
+ * see the present mode of your swapchain instead.
+ *
+ * @param[in] interval The minimum number of screen updates to wait for
+ * until the buffers are swapped by @ref glfwSwapBuffers.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @remark This function is not called during context creation, leaving the
+ * swap interval set to whatever is the default on that platform. This is done
+ * because some swap interval extensions used by GLFW do not allow the swap
+ * interval to be reset to zero once it has been set to a non-zero value.
+ *
+ * @remark Some GPU drivers do not honor the requested swap interval, either
+ * because of a user setting that overrides the application's request or due to
+ * bugs in the driver.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref buffer_swap
+ * @sa glfwSwapBuffers
+ *
+ * @since Added in version 1.0.
+ *
+ * @ingroup context
+ */
+GLFWAPI void glfwSwapInterval(int interval);
+
+/*! @brief Returns whether the specified extension is available.
+ *
+ * This function returns whether the specified
+ * [API extension](@ref context_glext) is supported by the current OpenGL or
+ * OpenGL ES context. It searches both for client API extension and context
+ * creation API extensions.
+ *
+ * A context must be current on the calling thread. Calling this function
+ * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error.
+ *
+ * As this functions retrieves and searches one or more extension strings each
+ * call, it is recommended that you cache its results if it is going to be used
+ * frequently. The extension strings will not change during the lifetime of
+ * a context, so there is no danger in doing this.
+ *
+ * This function does not apply to Vulkan. If you are using Vulkan, see @ref
+ * glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties`
+ * and `vkEnumerateDeviceExtensionProperties` instead.
+ *
+ * @param[in] extension The ASCII encoded name of the extension.
+ * @return `GLFW_TRUE` if the extension is available, or `GLFW_FALSE`
+ * otherwise.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_NO_CURRENT_CONTEXT, @ref GLFW_INVALID_VALUE and @ref
+ * GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref context_glext
+ * @sa glfwGetProcAddress
+ *
+ * @since Added in version 1.0.
+ *
+ * @ingroup context
+ */
+GLFWAPI int glfwExtensionSupported(const char* extension);
+
+/*! @brief Returns the address of the specified function for the current
+ * context.
+ *
+ * This function returns the address of the specified OpenGL or OpenGL ES
+ * [core or extension function](@ref context_glext), if it is supported
+ * by the current context.
+ *
+ * A context must be current on the calling thread. Calling this function
+ * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error.
+ *
+ * This function does not apply to Vulkan. If you are rendering with Vulkan,
+ * see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and
+ * `vkGetDeviceProcAddr` instead.
+ *
+ * @param[in] procname The ASCII encoded name of the function.
+ * @return The address of the function, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @remark The address of a given function is not guaranteed to be the same
+ * between contexts.
+ *
+ * @remark This function may return a non-`NULL` address despite the
+ * associated version or extension not being available. Always check the
+ * context version or extension string first.
+ *
+ * @pointer_lifetime The returned function pointer is valid until the context
+ * is destroyed or the library is terminated.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref context_glext
+ * @sa glfwExtensionSupported
+ *
+ * @since Added in version 1.0.
+ *
+ * @ingroup context
+ */
+GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname);
+
+/*! @brief Returns whether the Vulkan loader has been found.
+ *
+ * This function returns whether the Vulkan loader has been found. This check
+ * is performed by @ref glfwInit.
+ *
+ * The availability of a Vulkan loader does not by itself guarantee that window
+ * surface creation or even device creation is possible. Call @ref
+ * glfwGetRequiredInstanceExtensions to check whether the extensions necessary
+ * for Vulkan surface creation are available and @ref
+ * glfwGetPhysicalDevicePresentationSupport to check whether a queue family of
+ * a physical device supports image presentation.
+ *
+ * @return `GLFW_TRUE` if Vulkan is available, or `GLFW_FALSE` otherwise.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref vulkan_support
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup vulkan
+ */
+GLFWAPI int glfwVulkanSupported(void);
+
+/*! @brief Returns the Vulkan instance extensions required by GLFW.
+ *
+ * This function returns an array of names of Vulkan instance extensions required
+ * by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the
+ * list will always contains `VK_KHR_surface`, so if you don't require any
+ * additional extensions you can pass this list directly to the
+ * `VkInstanceCreateInfo` struct.
+ *
+ * If Vulkan is not available on the machine, this function returns `NULL` and
+ * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported
+ * to check whether Vulkan is available.
+ *
+ * If Vulkan is available but no set of extensions allowing window surface
+ * creation was found, this function returns `NULL`. You may still use Vulkan
+ * for off-screen rendering and compute work.
+ *
+ * @param[out] count Where to store the number of extensions in the returned
+ * array. This is set to zero if an error occurred.
+ * @return An array of ASCII encoded extension names, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_API_UNAVAILABLE.
+ *
+ * @remarks Additional extensions may be required by future versions of GLFW.
+ * You should check if any extensions you wish to enable are already in the
+ * returned array, as it is an error to specify an extension more than once in
+ * the `VkInstanceCreateInfo` struct.
+ *
+ * @pointer_lifetime The returned array is allocated and freed by GLFW. You
+ * should not free it yourself. It is guaranteed to be valid only until the
+ * library is terminated.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref vulkan_ext
+ * @sa glfwCreateWindowSurface
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup vulkan
+ */
+GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count);
+
+#if defined(VK_VERSION_1_0)
+
+/*! @brief Returns the address of the specified Vulkan instance function.
+ *
+ * This function returns the address of the specified Vulkan core or extension
+ * function for the specified instance. If instance is set to `NULL` it can
+ * return any function exported from the Vulkan loader, including at least the
+ * following functions:
+ *
+ * - `vkEnumerateInstanceExtensionProperties`
+ * - `vkEnumerateInstanceLayerProperties`
+ * - `vkCreateInstance`
+ * - `vkGetInstanceProcAddr`
+ *
+ * If Vulkan is not available on the machine, this function returns `NULL` and
+ * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported
+ * to check whether Vulkan is available.
+ *
+ * This function is equivalent to calling `vkGetInstanceProcAddr` with
+ * a platform-specific query of the Vulkan loader as a fallback.
+ *
+ * @param[in] instance The Vulkan instance to query, or `NULL` to retrieve
+ * functions related to instance creation.
+ * @param[in] procname The ASCII encoded name of the function.
+ * @return The address of the function, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ * GLFW_API_UNAVAILABLE.
+ *
+ * @pointer_lifetime The returned function pointer is valid until the library
+ * is terminated.
+ *
+ * @thread_safety This function may be called from any thread.
+ *
+ * @sa @ref vulkan_proc
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup vulkan
+ */
+GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname);
+
+/*! @brief Returns whether the specified queue family can present images.
+ *
+ * This function returns whether the specified queue family of the specified
+ * physical device supports presentation to the platform GLFW was built for.
+ *
+ * If Vulkan or the required window surface creation instance extensions are
+ * not available on the machine, or if the specified instance was not created
+ * with the required extensions, this function returns `GLFW_FALSE` and
+ * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported
+ * to check whether Vulkan is available and @ref
+ * glfwGetRequiredInstanceExtensions to check what instance extensions are
+ * required.
+ *
+ * @param[in] instance The instance that the physical device belongs to.
+ * @param[in] device The physical device that the queue family belongs to.
+ * @param[in] queuefamily The index of the queue family to query.
+ * @return `GLFW_TRUE` if the queue family supports presentation, or
+ * `GLFW_FALSE` otherwise.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @thread_safety This function may be called from any thread. For
+ * synchronization details of Vulkan objects, see the Vulkan specification.
+ *
+ * @sa @ref vulkan_present
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup vulkan
+ */
+GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
+
+/*! @brief Creates a Vulkan surface for the specified window.
+ *
+ * This function creates a Vulkan surface for the specified window.
+ *
+ * If the Vulkan loader was not found at initialization, this function returns
+ * `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref GLFW_API_UNAVAILABLE
+ * error. Call @ref glfwVulkanSupported to check whether the Vulkan loader was
+ * found.
+ *
+ * If the required window surface creation instance extensions are not
+ * available or if the specified instance was not created with these extensions
+ * enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and
+ * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref
+ * glfwGetRequiredInstanceExtensions to check what instance extensions are
+ * required.
+ *
+ * The window surface must be destroyed before the specified Vulkan instance.
+ * It is the responsibility of the caller to destroy the window surface. GLFW
+ * does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the
+ * surface.
+ *
+ * @param[in] instance The Vulkan instance to create the surface in.
+ * @param[in] window The window to create the surface for.
+ * @param[in] allocator The allocator to use, or `NULL` to use the default
+ * allocator.
+ * @param[out] surface Where to store the handle of the surface. This is set
+ * to `VK_NULL_HANDLE` if an error occurred.
+ * @return `VK_SUCCESS` if successful, or a Vulkan error code if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR.
+ *
+ * @remarks If an error occurs before the creation call is made, GLFW returns
+ * the Vulkan error code most appropriate for the error. Appropriate use of
+ * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should
+ * eliminate almost all occurrences of these errors.
+ *
+ * @thread_safety This function may be called from any thread. For
+ * synchronization details of Vulkan objects, see the Vulkan specification.
+ *
+ * @sa @ref vulkan_surface
+ * @sa glfwGetRequiredInstanceExtensions
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup vulkan
+ */
+GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
+
+#endif /*VK_VERSION_1_0*/
+
+
+/*************************************************************************
+ * Global definition cleanup
+ *************************************************************************/
+
+/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */
+
+#ifdef GLFW_WINGDIAPI_DEFINED
+ #undef WINGDIAPI
+ #undef GLFW_WINGDIAPI_DEFINED
+#endif
+
+#ifdef GLFW_CALLBACK_DEFINED
+ #undef CALLBACK
+ #undef GLFW_CALLBACK_DEFINED
+#endif
+
+/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _glfw3_h_ */
+
diff --git a/src/external/glfw3/include/GLFW/glfw3native.h b/src/external/glfw3/include/GLFW/glfw3native.h
new file mode 100644
index 00000000..30e1a570
--- /dev/null
+++ b/src/external/glfw3/include/GLFW/glfw3native.h
@@ -0,0 +1,456 @@
+/*************************************************************************
+ * GLFW 3.2 - www.glfw.org
+ * A library for OpenGL, window and input
+ *------------------------------------------------------------------------
+ * Copyright (c) 2002-2006 Marcus Geelnard
+ * Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would
+ * be appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ *
+ *************************************************************************/
+
+#ifndef _glfw3_native_h_
+#define _glfw3_native_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*************************************************************************
+ * Doxygen documentation
+ *************************************************************************/
+
+/*! @file glfw3native.h
+ * @brief The header of the native access functions.
+ *
+ * This is the header file of the native access functions. See @ref native for
+ * more information.
+ */
+/*! @defgroup native Native access
+ *
+ * **By using the native access functions you assert that you know what you're
+ * doing and how to fix problems caused by using them. If you don't, you
+ * shouldn't be using them.**
+ *
+ * Before the inclusion of @ref glfw3native.h, you may define exactly one
+ * window system API macro and zero or more context creation API macros.
+ *
+ * The chosen backends must match those the library was compiled for. Failure
+ * to do this will cause a link-time error.
+ *
+ * The available window API macros are:
+ * * `GLFW_EXPOSE_NATIVE_WIN32`
+ * * `GLFW_EXPOSE_NATIVE_COCOA`
+ * * `GLFW_EXPOSE_NATIVE_X11`
+ * * `GLFW_EXPOSE_NATIVE_WAYLAND`
+ * * `GLFW_EXPOSE_NATIVE_MIR`
+ *
+ * The available context API macros are:
+ * * `GLFW_EXPOSE_NATIVE_WGL`
+ * * `GLFW_EXPOSE_NATIVE_NSGL`
+ * * `GLFW_EXPOSE_NATIVE_GLX`
+ * * `GLFW_EXPOSE_NATIVE_EGL`
+ *
+ * These macros select which of the native access functions that are declared
+ * and which platform-specific headers to include. It is then up your (by
+ * definition platform-specific) code to handle which of these should be
+ * defined.
+ */
+
+
+/*************************************************************************
+ * System headers and types
+ *************************************************************************/
+
+#if defined(GLFW_EXPOSE_NATIVE_WIN32)
+ // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
+ // example to allow applications to correctly declare a GL_ARB_debug_output
+ // callback) but windows.h assumes no one will define APIENTRY before it does
+ #undef APIENTRY
+ #include <windows.h>
+#elif defined(GLFW_EXPOSE_NATIVE_COCOA)
+ #include <ApplicationServices/ApplicationServices.h>
+ #if defined(__OBJC__)
+ #import <Cocoa/Cocoa.h>
+ #else
+ typedef void* id;
+ #endif
+#elif defined(GLFW_EXPOSE_NATIVE_X11)
+ #include <X11/Xlib.h>
+ #include <X11/extensions/Xrandr.h>
+#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
+ #include <wayland-client.h>
+#elif defined(GLFW_EXPOSE_NATIVE_MIR)
+ #include <mir_toolkit/mir_client_library.h>
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_WGL)
+ /* WGL is declared by windows.h */
+#endif
+#if defined(GLFW_EXPOSE_NATIVE_NSGL)
+ /* NSGL is declared by Cocoa.h */
+#endif
+#if defined(GLFW_EXPOSE_NATIVE_GLX)
+ #include <GL/glx.h>
+#endif
+#if defined(GLFW_EXPOSE_NATIVE_EGL)
+ #include <EGL/egl.h>
+#endif
+
+
+/*************************************************************************
+ * Functions
+ *************************************************************************/
+
+#if defined(GLFW_EXPOSE_NATIVE_WIN32)
+/*! @brief Returns the adapter device name of the specified monitor.
+ *
+ * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`)
+ * of the specified monitor, or `NULL` if an [error](@ref error_handling)
+ * occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup native
+ */
+GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor);
+
+/*! @brief Returns the display device name of the specified monitor.
+ *
+ * @return The UTF-8 encoded display device name (for example
+ * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup native
+ */
+GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor);
+
+/*! @brief Returns the `HWND` of the specified window.
+ *
+ * @return The `HWND` of the specified window, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup native
+ */
+GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window);
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_WGL)
+/*! @brief Returns the `HGLRC` of the specified window.
+ *
+ * @return The `HGLRC` of the specified window, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup native
+ */
+GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window);
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_COCOA)
+/*! @brief Returns the `CGDirectDisplayID` of the specified monitor.
+ *
+ * @return The `CGDirectDisplayID` of the specified monitor, or
+ * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup native
+ */
+GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor);
+
+/*! @brief Returns the `NSWindow` of the specified window.
+ *
+ * @return The `NSWindow` of the specified window, or `nil` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup native
+ */
+GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window);
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_NSGL)
+/*! @brief Returns the `NSOpenGLContext` of the specified window.
+ *
+ * @return The `NSOpenGLContext` of the specified window, or `nil` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup native
+ */
+GLFWAPI id glfwGetNSGLContext(GLFWwindow* window);
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_X11)
+/*! @brief Returns the `Display` used by GLFW.
+ *
+ * @return The `Display` used by GLFW, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup native
+ */
+GLFWAPI Display* glfwGetX11Display(void);
+
+/*! @brief Returns the `RRCrtc` of the specified monitor.
+ *
+ * @return The `RRCrtc` of the specified monitor, or `None` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup native
+ */
+GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor);
+
+/*! @brief Returns the `RROutput` of the specified monitor.
+ *
+ * @return The `RROutput` of the specified monitor, or `None` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.1.
+ *
+ * @ingroup native
+ */
+GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor);
+
+/*! @brief Returns the `Window` of the specified window.
+ *
+ * @return The `Window` of the specified window, or `None` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup native
+ */
+GLFWAPI Window glfwGetX11Window(GLFWwindow* window);
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_GLX)
+/*! @brief Returns the `GLXContext` of the specified window.
+ *
+ * @return The `GLXContext` of the specified window, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup native
+ */
+GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window);
+
+/*! @brief Returns the `GLXWindow` of the specified window.
+ *
+ * @return The `GLXWindow` of the specified window, or `None` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup native
+ */
+GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window);
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
+/*! @brief Returns the `struct wl_display*` used by GLFW.
+ *
+ * @return The `struct wl_display*` used by GLFW, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup native
+ */
+GLFWAPI struct wl_display* glfwGetWaylandDisplay(void);
+
+/*! @brief Returns the `struct wl_output*` of the specified monitor.
+ *
+ * @return The `struct wl_output*` of the specified monitor, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup native
+ */
+GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
+
+/*! @brief Returns the main `struct wl_surface*` of the specified window.
+ *
+ * @return The main `struct wl_surface*` of the specified window, or `NULL` if
+ * an [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup native
+ */
+GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_MIR)
+/*! @brief Returns the `MirConnection*` used by GLFW.
+ *
+ * @return The `MirConnection*` used by GLFW, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup native
+ */
+GLFWAPI MirConnection* glfwGetMirDisplay(void);
+
+/*! @brief Returns the Mir output ID of the specified monitor.
+ *
+ * @return The Mir output ID of the specified monitor, or zero if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup native
+ */
+GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor);
+
+/*! @brief Returns the `MirSurface*` of the specified window.
+ *
+ * @return The `MirSurface*` of the specified window, or `NULL` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.2.
+ *
+ * @ingroup native
+ */
+GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window);
+#endif
+
+#if defined(GLFW_EXPOSE_NATIVE_EGL)
+/*! @brief Returns the `EGLDisplay` used by GLFW.
+ *
+ * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup native
+ */
+GLFWAPI EGLDisplay glfwGetEGLDisplay(void);
+
+/*! @brief Returns the `EGLContext` of the specified window.
+ *
+ * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup native
+ */
+GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window);
+
+/*! @brief Returns the `EGLSurface` of the specified window.
+ *
+ * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an
+ * [error](@ref error_handling) occurred.
+ *
+ * @thread_safety This function may be called from any thread. Access is not
+ * synchronized.
+ *
+ * @since Added in version 3.0.
+ *
+ * @ingroup native
+ */
+GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _glfw3_native_h_ */
+
diff --git a/src/external/glfw3/lib/linux/libglfw3.a b/src/external/glfw3/lib/linux/libglfw3.a
new file mode 100644
index 00000000..84cc1d20
--- /dev/null
+++ b/src/external/glfw3/lib/linux/libglfw3.a
Binary files differ
diff --git a/src/external/glfw3/lib/osx/libglfw.3.0.dylib b/src/external/glfw3/lib/osx/libglfw.3.0.dylib
new file mode 100644
index 00000000..15674573
--- /dev/null
+++ b/src/external/glfw3/lib/osx/libglfw.3.0.dylib
Binary files differ
diff --git a/src/external/glfw3/lib/osx/libglfw.3.dylib b/src/external/glfw3/lib/osx/libglfw.3.dylib
new file mode 100644
index 00000000..cd20112e
--- /dev/null
+++ b/src/external/glfw3/lib/osx/libglfw.3.dylib
@@ -0,0 +1 @@
+libglfw.3.0.dylib \ No newline at end of file
diff --git a/src/external/glfw3/lib/osx/libglfw.dylib b/src/external/glfw3/lib/osx/libglfw.dylib
new file mode 100644
index 00000000..d4bd51e1
--- /dev/null
+++ b/src/external/glfw3/lib/osx/libglfw.dylib
@@ -0,0 +1 @@
+libglfw.3.dylib \ No newline at end of file
diff --git a/src/external/glfw3/lib/win32/glfw3.dll b/src/external/glfw3/lib/win32/glfw3.dll
new file mode 100644
index 00000000..9f5d40f6
--- /dev/null
+++ b/src/external/glfw3/lib/win32/glfw3.dll
Binary files differ
diff --git a/src/external/glfw3/lib/win32/libglfw3.a b/src/external/glfw3/lib/win32/libglfw3.a
new file mode 100644
index 00000000..d50ffa72
--- /dev/null
+++ b/src/external/glfw3/lib/win32/libglfw3.a
Binary files differ
diff --git a/src/external/glfw3/lib/win32/libglfw3dll.a b/src/external/glfw3/lib/win32/libglfw3dll.a
new file mode 100644
index 00000000..a42a400b
--- /dev/null
+++ b/src/external/glfw3/lib/win32/libglfw3dll.a
Binary files differ
diff --git a/src/external/jar_mod.h b/src/external/jar_mod.h
new file mode 100644
index 00000000..c17130a6
--- /dev/null
+++ b/src/external/jar_mod.h
@@ -0,0 +1,1594 @@
+// jar_mod.h - v0.01 - public domain C0 - Joshua Reisenauer
+//
+// HISTORY:
+//
+// v0.01 2016-03-12 Setup
+//
+//
+// USAGE:
+//
+// In ONE source file, put:
+//
+// #define JAR_MOD_IMPLEMENTATION
+// #include "jar_mod.h"
+//
+// Other source files should just include jar_mod.h
+//
+// SAMPLE CODE:
+// jar_mod_context_t modctx;
+// short samplebuff[4096];
+// bool bufferFull = false;
+// int intro_load(void)
+// {
+// jar_mod_init(&modctx);
+// jar_mod_load_file(&modctx, "file.mod");
+// return 1;
+// }
+// int intro_unload(void)
+// {
+// jar_mod_unload(&modctx);
+// return 1;
+// }
+// int intro_tick(long counter)
+// {
+// if(!bufferFull)
+// {
+// jar_mod_fillbuffer(&modctx, samplebuff, 4096, 0);
+// bufferFull=true;
+// }
+// if(IsKeyDown(KEY_ENTER))
+// return 1;
+// return 0;
+// }
+//
+//
+// LISCENSE:
+//
+// Written by: Jean-François DEL NERO (http://hxc2001.com/) <Email : jeanfrancoisdelnero <> free.fr>
+// Adapted to jar_mod by: Joshua Adam Reisenauer <kd7tck@gmail.com>
+// This program is free software. It comes without any warranty, to the
+// extent permitted by applicable law. You can redistribute it and/or
+// modify it under the terms of the Do What The Fuck You Want To Public
+// License, Version 2, as published by Sam Hocevar. See
+// http://sam.zoy.org/wtfpl/COPYING for more details.
+///////////////////////////////////////////////////////////////////////////////////
+// HxCMOD Core API:
+// -------------------------------------------
+// int jar_mod_init(jar_mod_context_t * modctx)
+//
+// - Initialize the jar_mod_context_t buffer. Must be called before doing anything else.
+// Return 1 if success. 0 in case of error.
+// -------------------------------------------
+// mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename)
+//
+// - "Load" a MOD from file, context must already be initialized.
+// Return size of file in bytes.
+// -------------------------------------------
+// void jar_mod_fillbuffer( jar_mod_context_t * modctx, short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf )
+//
+// - Generate and return the next samples chunk to outbuffer.
+// nbsample specify the number of stereo 16bits samples you want.
+// The output format is by default signed 48000Hz 16-bit Stereo PCM samples, otherwise it is changed with jar_mod_setcfg().
+// The output buffer size in bytes must be equal to ( nbsample * 2 * channels ).
+// The optional trkbuf parameter can be used to get detailed status of the player. Put NULL/0 is unused.
+// -------------------------------------------
+// void jar_mod_unload( jar_mod_context_t * modctx )
+// - "Unload" / clear the player status.
+// -------------------------------------------
+///////////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef INCLUDE_JAR_MOD_H
+#define INCLUDE_JAR_MOD_H
+
+#include <stdio.h>
+#include <stdlib.h>
+//#include <stdbool.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+// Basic type
+typedef unsigned char muchar;
+typedef unsigned short muint;
+typedef short mint;
+typedef unsigned long mulong;
+
+#define NUMMAXCHANNELS 32
+#define MAXNOTES 12*12
+#define DEFAULT_SAMPLE_RATE 48000
+//
+// MOD file structures
+//
+
+#pragma pack(1)
+
+typedef struct {
+ muchar name[22];
+ muint length;
+ muchar finetune;
+ muchar volume;
+ muint reppnt;
+ muint replen;
+} sample;
+
+typedef struct {
+ muchar sampperiod;
+ muchar period;
+ muchar sampeffect;
+ muchar effect;
+} note;
+
+typedef struct {
+ muchar title[20];
+ sample samples[31];
+ muchar length; // length of tablepos
+ muchar protracker;
+ muchar patterntable[128];
+ muchar signature[4];
+ muchar speed;
+} module;
+
+#pragma pack()
+
+//
+// HxCMod Internal structures
+//
+typedef struct {
+ char* sampdata;
+ muint sampnum;
+ muint length;
+ muint reppnt;
+ muint replen;
+ mulong samppos;
+ muint period;
+ muchar volume;
+ mulong ticks;
+ muchar effect;
+ muchar parameffect;
+ muint effect_code;
+ mint decalperiod;
+ mint portaspeed;
+ mint portaperiod;
+ mint vibraperiod;
+ mint Arpperiods[3];
+ muchar ArpIndex;
+ mint oldk;
+ muchar volumeslide;
+ muchar vibraparam;
+ muchar vibrapointeur;
+ muchar finetune;
+ muchar cut_param;
+ muint patternloopcnt;
+ muint patternloopstartpoint;
+} channel;
+
+typedef struct {
+ module song;
+ char* sampledata[31];
+ note* patterndata[128];
+
+ mulong playrate;
+ muint tablepos;
+ muint patternpos;
+ muint patterndelay;
+ muint jump_loop_effect;
+ muchar bpm;
+ mulong patternticks;
+ mulong patterntickse;
+ mulong patternticksaim;
+ mulong sampleticksconst;
+ mulong samplenb;
+ channel channels[NUMMAXCHANNELS];
+ muint number_of_channels;
+ muint fullperiod[MAXNOTES * 8];
+ muint mod_loaded;
+ mint last_r_sample;
+ mint last_l_sample;
+ mint stereo;
+ mint stereo_separation;
+ mint bits;
+ mint filter;
+
+ muchar *modfile; // the raw mod file
+ mulong modfilesize;
+ muint loopcount;
+} jar_mod_context_t;
+
+//
+// Player states structures
+//
+typedef struct track_state_
+{
+ unsigned char instrument_number;
+ unsigned short cur_period;
+ unsigned char cur_volume;
+ unsigned short cur_effect;
+ unsigned short cur_parameffect;
+}track_state;
+
+typedef struct tracker_state_
+{
+ int number_of_tracks;
+ int bpm;
+ int speed;
+ int cur_pattern;
+ int cur_pattern_pos;
+ int cur_pattern_table_pos;
+ unsigned int buf_index;
+ track_state tracks[32];
+}tracker_state;
+
+typedef struct tracker_state_instrument_
+{
+ char name[22];
+ int active;
+}tracker_state_instrument;
+
+typedef struct jar_mod_tracker_buffer_state_
+{
+ int nb_max_of_state;
+ int nb_of_state;
+ int cur_rd_index;
+ int sample_step;
+ char name[64];
+ tracker_state_instrument instruments[31];
+ tracker_state * track_state_buf;
+}jar_mod_tracker_buffer_state;
+
+
+
+bool jar_mod_init(jar_mod_context_t * modctx);
+bool jar_mod_setcfg(jar_mod_context_t * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter);
+void jar_mod_fillbuffer(jar_mod_context_t * modctx, short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf);
+void jar_mod_unload(jar_mod_context_t * modctx);
+mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename);
+mulong jar_mod_current_samples(jar_mod_context_t * modctx);
+mulong jar_mod_max_samples(jar_mod_context_t * modctx);
+void jar_mod_seek_start(jar_mod_context_t * ctx);
+
+#ifdef __cplusplus
+}
+#endif
+//--------------------------------------------------------------------
+
+
+
+//-------------------------------------------------------------------------------
+#ifdef JAR_MOD_IMPLEMENTATION
+
+// Effects list
+#define EFFECT_ARPEGGIO 0x0 // Supported
+#define EFFECT_PORTAMENTO_UP 0x1 // Supported
+#define EFFECT_PORTAMENTO_DOWN 0x2 // Supported
+#define EFFECT_TONE_PORTAMENTO 0x3 // Supported
+#define EFFECT_VIBRATO 0x4 // Supported
+#define EFFECT_VOLSLIDE_TONEPORTA 0x5 // Supported
+#define EFFECT_VOLSLIDE_VIBRATO 0x6 // Supported
+#define EFFECT_VOLSLIDE_TREMOLO 0x7 // - TO BE DONE -
+#define EFFECT_SET_PANNING 0x8 // - TO BE DONE -
+#define EFFECT_SET_OFFSET 0x9 // Supported
+#define EFFECT_VOLUME_SLIDE 0xA // Supported
+#define EFFECT_JUMP_POSITION 0xB // Supported
+#define EFFECT_SET_VOLUME 0xC // Supported
+#define EFFECT_PATTERN_BREAK 0xD // Supported
+
+#define EFFECT_EXTENDED 0xE
+#define EFFECT_E_FINE_PORTA_UP 0x1 // Supported
+#define EFFECT_E_FINE_PORTA_DOWN 0x2 // Supported
+#define EFFECT_E_GLISSANDO_CTRL 0x3 // - TO BE DONE -
+#define EFFECT_E_VIBRATO_WAVEFORM 0x4 // - TO BE DONE -
+#define EFFECT_E_SET_FINETUNE 0x5 // - TO BE DONE -
+#define EFFECT_E_PATTERN_LOOP 0x6 // Supported
+#define EFFECT_E_TREMOLO_WAVEFORM 0x7 // - TO BE DONE -
+#define EFFECT_E_SET_PANNING_2 0x8 // - TO BE DONE -
+#define EFFECT_E_RETRIGGER_NOTE 0x9 // - TO BE DONE -
+#define EFFECT_E_FINE_VOLSLIDE_UP 0xA // Supported
+#define EFFECT_E_FINE_VOLSLIDE_DOWN 0xB // Supported
+#define EFFECT_E_NOTE_CUT 0xC // Supported
+#define EFFECT_E_NOTE_DELAY 0xD // - TO BE DONE -
+#define EFFECT_E_PATTERN_DELAY 0xE // Supported
+#define EFFECT_E_INVERT_LOOP 0xF // - TO BE DONE -
+#define EFFECT_SET_SPEED 0xF0 // Supported
+#define EFFECT_SET_TEMPO 0xF2 // Supported
+
+#define PERIOD_TABLE_LENGTH MAXNOTES
+#define FULL_PERIOD_TABLE_LENGTH ( PERIOD_TABLE_LENGTH * 8 )
+
+static const short periodtable[]=
+{
+ 27392, 25856, 24384, 23040, 21696, 20480, 19328, 18240, 17216, 16256, 15360, 14496,
+ 13696, 12928, 12192, 11520, 10848, 10240, 9664, 9120, 8606, 8128, 7680, 7248,
+ 6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4064, 3840, 3624,
+ 3424, 3232, 3048, 2880, 2712, 2560, 2416, 2280, 2152, 2032, 1920, 1812,
+ 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 906,
+ 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453,
+ 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226,
+ 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113,
+ 107, 101, 95, 90, 85, 80, 75, 71, 67, 63, 60, 56,
+ 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28,
+ 27, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 14,
+ 13, 13, 12, 11, 11, 10, 9, 9, 8, 8, 7, 7
+};
+
+static const short sintable[]={
+ 0, 24, 49, 74, 97, 120, 141,161,
+ 180, 197, 212, 224, 235, 244, 250,253,
+ 255, 253, 250, 244, 235, 224, 212,197,
+ 180, 161, 141, 120, 97, 74, 49, 24
+};
+
+typedef struct modtype_
+{
+ unsigned char signature[5];
+ int numberofchannels;
+}modtype;
+
+modtype modlist[]=
+{
+ { "M!K!",4},
+ { "M.K.",4},
+ { "FLT4",4},
+ { "FLT8",8},
+ { "4CHN",4},
+ { "6CHN",6},
+ { "8CHN",8},
+ { "10CH",10},
+ { "12CH",12},
+ { "14CH",14},
+ { "16CH",16},
+ { "18CH",18},
+ { "20CH",20},
+ { "22CH",22},
+ { "24CH",24},
+ { "26CH",26},
+ { "28CH",28},
+ { "30CH",30},
+ { "32CH",32},
+ { "",0}
+};
+
+///////////////////////////////////////////////////////////////////////////////////
+
+static void memcopy( void * dest, void *source, unsigned long size )
+{
+ unsigned long i;
+ unsigned char * d,*s;
+
+ d=(unsigned char*)dest;
+ s=(unsigned char*)source;
+ for(i=0;i<size;i++)
+ {
+ d[i]=s[i];
+ }
+}
+
+static void memclear( void * dest, unsigned char value, unsigned long size )
+{
+ unsigned long i;
+ unsigned char * d;
+
+ d=(unsigned char*)dest;
+ for(i=0;i<size;i++)
+ {
+ d[i]=value;
+ }
+}
+
+static int memcompare( unsigned char * buf1, unsigned char * buf2, unsigned int size )
+{
+ unsigned int i;
+
+ i = 0;
+
+ while(i<size)
+ {
+ if(buf1[i] != buf2[i])
+ {
+ return 0;
+ }
+ i++;
+ }
+
+ return 1;
+}
+
+static int getnote( jar_mod_context_t * mod, unsigned short period, int finetune )
+{
+ int i;
+
+ for(i = 0; i < FULL_PERIOD_TABLE_LENGTH; i++)
+ {
+ if(period >= mod->fullperiod[i])
+ {
+ return i;
+ }
+ }
+
+ return MAXNOTES;
+}
+
+static void worknote( note * nptr, channel * cptr, char t, jar_mod_context_t * mod )
+{
+ muint sample, period, effect, operiod;
+ muint curnote, arpnote;
+
+ sample = (nptr->sampperiod & 0xF0) | (nptr->sampeffect >> 4);
+ period = ((nptr->sampperiod & 0xF) << 8) | nptr->period;
+ effect = ((nptr->sampeffect & 0xF) << 8) | nptr->effect;
+
+ operiod = cptr->period;
+
+ if ( period || sample )
+ {
+ if( sample && sample < 32 )
+ {
+ cptr->sampnum = sample - 1;
+ }
+
+ if( period || sample )
+ {
+ cptr->sampdata = (char *) mod->sampledata[cptr->sampnum];
+ cptr->length = mod->song.samples[cptr->sampnum].length;
+ cptr->reppnt = mod->song.samples[cptr->sampnum].reppnt;
+ cptr->replen = mod->song.samples[cptr->sampnum].replen;
+
+ cptr->finetune = (mod->song.samples[cptr->sampnum].finetune)&0xF;
+
+ if(effect>>8!=4 && effect>>8!=6)
+ {
+ cptr->vibraperiod=0;
+ cptr->vibrapointeur=0;
+ }
+ }
+
+ if( (sample != 0) && ( (effect>>8) != EFFECT_VOLSLIDE_TONEPORTA ) )
+ {
+ cptr->volume = mod->song.samples[cptr->sampnum].volume;
+ cptr->volumeslide = 0;
+ }
+
+ if( ( (effect>>8) != EFFECT_TONE_PORTAMENTO && (effect>>8)!=EFFECT_VOLSLIDE_TONEPORTA) )
+ {
+ if (period!=0)
+ cptr->samppos = 0;
+ }
+
+ cptr->decalperiod = 0;
+ if( period )
+ {
+ if(cptr->finetune)
+ {
+ if( cptr->finetune <= 7 )
+ {
+ period = mod->fullperiod[getnote(mod,period,0) + cptr->finetune];
+ }
+ else
+ {
+ period = mod->fullperiod[getnote(mod,period,0) - (16 - (cptr->finetune)) ];
+ }
+ }
+
+ cptr->period = period;
+ }
+
+ }
+
+ cptr->effect = 0;
+ cptr->parameffect = 0;
+ cptr->effect_code = effect;
+
+ switch (effect >> 8)
+ {
+ case EFFECT_ARPEGGIO:
+ /*
+ [0]: Arpeggio
+ Where [0][x][y] means "play note, note+x semitones, note+y
+ semitones, then return to original note". The fluctuations are
+ carried out evenly spaced in one pattern division. They are usually
+ used to simulate chords, but this doesn't work too well. They are
+ also used to produce heavy vibrato. A major chord is when x=4, y=7.
+ A minor chord is when x=3, y=7.
+ */
+
+ if(effect&0xff)
+ {
+ cptr->effect = EFFECT_ARPEGGIO;
+ cptr->parameffect = effect&0xff;
+
+ cptr->ArpIndex = 0;
+
+ curnote = getnote(mod,cptr->period,cptr->finetune);
+
+ cptr->Arpperiods[0] = cptr->period;
+
+ arpnote = curnote + (((cptr->parameffect>>4)&0xF)*8);
+ if( arpnote >= FULL_PERIOD_TABLE_LENGTH )
+ arpnote = FULL_PERIOD_TABLE_LENGTH - 1;
+
+ cptr->Arpperiods[1] = mod->fullperiod[arpnote];
+
+ arpnote = curnote + (((cptr->parameffect)&0xF)*8);
+ if( arpnote >= FULL_PERIOD_TABLE_LENGTH )
+ arpnote = FULL_PERIOD_TABLE_LENGTH - 1;
+
+ cptr->Arpperiods[2] = mod->fullperiod[arpnote];
+ }
+ break;
+
+ case EFFECT_PORTAMENTO_UP:
+ /*
+ [1]: Slide up
+ Where [1][x][y] means "smoothly decrease the period of current
+ sample by x*16+y after each tick in the division". The
+ ticks/division are set with the 'set speed' effect (see below). If
+ the period of the note being played is z, then the final period
+ will be z - (x*16 + y)*(ticks - 1). As the slide rate depends on
+ the speed, changing the speed will change the slide. You cannot
+ slide beyond the note B3 (period 113).
+ */
+
+ cptr->effect = EFFECT_PORTAMENTO_UP;
+ cptr->parameffect = effect&0xff;
+ break;
+
+ case EFFECT_PORTAMENTO_DOWN:
+ /*
+ [2]: Slide down
+ Where [2][x][y] means "smoothly increase the period of current
+ sample by x*16+y after each tick in the division". Similar to [1],
+ but lowers the pitch. You cannot slide beyond the note C1 (period
+ 856).
+ */
+
+ cptr->effect = EFFECT_PORTAMENTO_DOWN;
+ cptr->parameffect = effect&0xff;
+ break;
+
+ case EFFECT_TONE_PORTAMENTO:
+ /*
+ [3]: Slide to note
+ Where [3][x][y] means "smoothly change the period of current sample
+ by x*16+y after each tick in the division, never sliding beyond
+ current period". The period-length in this channel's division is a
+ parameter to this effect, and hence is not played. Sliding to a
+ note is similar to effects [1] and [2], but the slide will not go
+ beyond the given period, and the direction is implied by that
+ period. If x and y are both 0, then the old slide will continue.
+ */
+
+ cptr->effect = EFFECT_TONE_PORTAMENTO;
+ if( (effect&0xff) != 0 )
+ {
+ cptr->portaspeed = (short)(effect&0xff);
+ }
+
+ if(period!=0)
+ {
+ cptr->portaperiod = period;
+ cptr->period = operiod;
+ }
+ break;
+
+ case EFFECT_VIBRATO:
+ /*
+ [4]: Vibrato
+ Where [4][x][y] means "oscillate the sample pitch using a
+ particular waveform with amplitude y/16 semitones, such that (x *
+ ticks)/64 cycles occur in the division". The waveform is set using
+ effect [14][4]. By placing vibrato effects on consecutive
+ divisions, the vibrato effect can be maintained. If either x or y
+ are 0, then the old vibrato values will be used.
+ */
+
+ cptr->effect = EFFECT_VIBRATO;
+ if( ( effect & 0x0F ) != 0 ) // Depth continue or change ?
+ cptr->vibraparam = (cptr->vibraparam & 0xF0) | ( effect & 0x0F );
+ if( ( effect & 0xF0 ) != 0 ) // Speed continue or change ?
+ cptr->vibraparam = (cptr->vibraparam & 0x0F) | ( effect & 0xF0 );
+
+ break;
+
+ case EFFECT_VOLSLIDE_TONEPORTA:
+ /*
+ [5]: Continue 'Slide to note', but also do Volume slide
+ Where [5][x][y] means "either slide the volume up x*(ticks - 1) or
+ slide the volume down y*(ticks - 1), at the same time as continuing
+ the last 'Slide to note'". It is illegal for both x and y to be
+ non-zero. You cannot slide outside the volume range 0..64. The
+ period-length in this channel's division is a parameter to this
+ effect, and hence is not played.
+ */
+
+ if( period != 0 )
+ {
+ cptr->portaperiod = period;
+ cptr->period = operiod;
+ }
+
+ cptr->effect = EFFECT_VOLSLIDE_TONEPORTA;
+ if( ( effect & 0xFF ) != 0 )
+ cptr->volumeslide = ( effect & 0xFF );
+
+ break;
+
+ case EFFECT_VOLSLIDE_VIBRATO:
+ /*
+ [6]: Continue 'Vibrato', but also do Volume slide
+ Where [6][x][y] means "either slide the volume up x*(ticks - 1) or
+ slide the volume down y*(ticks - 1), at the same time as continuing
+ the last 'Vibrato'". It is illegal for both x and y to be non-zero.
+ You cannot slide outside the volume range 0..64.
+ */
+
+ cptr->effect = EFFECT_VOLSLIDE_VIBRATO;
+ if( (effect & 0xFF) != 0 )
+ cptr->volumeslide = (effect & 0xFF);
+ break;
+
+ case EFFECT_SET_OFFSET:
+ /*
+ [9]: Set sample offset
+ Where [9][x][y] means "play the sample from offset x*4096 + y*256".
+ The offset is measured in words. If no sample is given, yet one is
+ still playing on this channel, it should be retriggered to the new
+ offset using the current volume.
+ */
+
+ cptr->samppos = ((effect>>4) * 4096) + ((effect&0xF)*256);
+
+ break;
+
+ case EFFECT_VOLUME_SLIDE:
+ /*
+ [10]: Volume slide
+ Where [10][x][y] means "either slide the volume up x*(ticks - 1) or
+ slide the volume down y*(ticks - 1)". If both x and y are non-zero,
+ then the y value is ignored (assumed to be 0). You cannot slide
+ outside the volume range 0..64.
+ */
+
+ cptr->effect = EFFECT_VOLUME_SLIDE;
+ cptr->volumeslide = (effect & 0xFF);
+ break;
+
+ case EFFECT_JUMP_POSITION:
+ /*
+ [11]: Position Jump
+ Where [11][x][y] means "stop the pattern after this division, and
+ continue the song at song-position x*16+y". This shifts the
+ 'pattern-cursor' in the pattern table (see above). Legal values for
+ x*16+y are from 0 to 127.
+ */
+
+ mod->tablepos = (effect & 0xFF);
+ if(mod->tablepos >= mod->song.length)
+ {
+ mod->tablepos = 0;
+ }
+ mod->patternpos = 0;
+ mod->jump_loop_effect = 1;
+
+ break;
+
+ case EFFECT_SET_VOLUME:
+ /*
+ [12]: Set volume
+ Where [12][x][y] means "set current sample's volume to x*16+y".
+ Legal volumes are 0..64.
+ */
+
+ cptr->volume = (effect & 0xFF);
+ break;
+
+ case EFFECT_PATTERN_BREAK:
+ /*
+ [13]: Pattern Break
+ Where [13][x][y] means "stop the pattern after this division, and
+ continue the song at the next pattern at division x*10+y" (the 10
+ is not a typo). Legal divisions are from 0 to 63 (note Protracker
+ exception above).
+ */
+
+ mod->patternpos = ( ((effect>>4)&0xF)*10 + (effect&0xF) ) * mod->number_of_channels;
+ mod->jump_loop_effect = 1;
+ mod->tablepos++;
+ if(mod->tablepos >= mod->song.length)
+ {
+ mod->tablepos = 0;
+ }
+
+ break;
+
+ case EFFECT_EXTENDED:
+ switch( (effect>>4) & 0xF )
+ {
+ case EFFECT_E_FINE_PORTA_UP:
+ /*
+ [14][1]: Fineslide up
+ Where [14][1][x] means "decrement the period of the current sample
+ by x". The incrementing takes place at the beginning of the
+ division, and hence there is no actual sliding. You cannot slide
+ beyond the note B3 (period 113).
+ */
+
+ cptr->period -= (effect & 0xF);
+ if( cptr->period < 113 )
+ cptr->period = 113;
+ break;
+
+ case EFFECT_E_FINE_PORTA_DOWN:
+ /*
+ [14][2]: Fineslide down
+ Where [14][2][x] means "increment the period of the current sample
+ by x". Similar to [14][1] but shifts the pitch down. You cannot
+ slide beyond the note C1 (period 856).
+ */
+
+ cptr->period += (effect & 0xF);
+ if( cptr->period > 856 )
+ cptr->period = 856;
+ break;
+
+ case EFFECT_E_FINE_VOLSLIDE_UP:
+ /*
+ [14][10]: Fine volume slide up
+ Where [14][10][x] means "increment the volume of the current sample
+ by x". The incrementing takes place at the beginning of the
+ division, and hence there is no sliding. You cannot slide beyond
+ volume 64.
+ */
+
+ cptr->volume += (effect & 0xF);
+ if( cptr->volume>64 )
+ cptr->volume = 64;
+ break;
+
+ case EFFECT_E_FINE_VOLSLIDE_DOWN:
+ /*
+ [14][11]: Fine volume slide down
+ Where [14][11][x] means "decrement the volume of the current sample
+ by x". Similar to [14][10] but lowers volume. You cannot slide
+ beyond volume 0.
+ */
+
+ cptr->volume -= (effect & 0xF);
+ if( cptr->volume > 200 )
+ cptr->volume = 0;
+ break;
+
+ case EFFECT_E_PATTERN_LOOP:
+ /*
+ [14][6]: Loop pattern
+ Where [14][6][x] means "set the start of a loop to this division if
+ x is 0, otherwise after this division, jump back to the start of a
+ loop and play it another x times before continuing". If the start
+ of the loop was not set, it will default to the start of the
+ current pattern. Hence 'loop pattern' cannot be performed across
+ multiple patterns. Note that loops do not support nesting, and you
+ may generate an infinite loop if you try to nest 'loop pattern's.
+ */
+
+ if( effect & 0xF )
+ {
+ if( cptr->patternloopcnt )
+ {
+ cptr->patternloopcnt--;
+ if( cptr->patternloopcnt )
+ {
+ mod->patternpos = cptr->patternloopstartpoint;
+ mod->jump_loop_effect = 1;
+ }
+ else
+ {
+ cptr->patternloopstartpoint = mod->patternpos ;
+ }
+ }
+ else
+ {
+ cptr->patternloopcnt = (effect & 0xF);
+ mod->patternpos = cptr->patternloopstartpoint;
+ mod->jump_loop_effect = 1;
+ }
+ }
+ else // Start point
+ {
+ cptr->patternloopstartpoint = mod->patternpos;
+ }
+
+ break;
+
+ case EFFECT_E_PATTERN_DELAY:
+ /*
+ [14][14]: Delay pattern
+ Where [14][14][x] means "after this division there will be a delay
+ equivalent to the time taken to play x divisions after which the
+ pattern will be resumed". The delay only relates to the
+ interpreting of new divisions, and all effects and previous notes
+ continue during delay.
+ */
+
+ mod->patterndelay = (effect & 0xF);
+ break;
+
+ case EFFECT_E_NOTE_CUT:
+ /*
+ [14][12]: Cut sample
+ Where [14][12][x] means "after the current sample has been played
+ for x ticks in this division, its volume will be set to 0". This
+ implies that if x is 0, then you will not hear any of the sample.
+ If you wish to insert "silence" in a pattern, it is better to use a
+ "silence"-sample (see above) due to the lack of proper support for
+ this effect.
+ */
+ cptr->effect = EFFECT_E_NOTE_CUT;
+ cptr->cut_param = (effect & 0xF);
+ if(!cptr->cut_param)
+ cptr->volume = 0;
+ break;
+
+ default:
+
+ break;
+ }
+ break;
+
+ case 0xF:
+ /*
+ [15]: Set speed
+ Where [15][x][y] means "set speed to x*16+y". Though it is nowhere
+ near that simple. Let z = x*16+y. Depending on what values z takes,
+ different units of speed are set, there being two: ticks/division
+ and beats/minute (though this one is only a label and not strictly
+ true). If z=0, then what should technically happen is that the
+ module stops, but in practice it is treated as if z=1, because
+ there is already a method for stopping the module (running out of
+ patterns). If z<=32, then it means "set ticks/division to z"
+ otherwise it means "set beats/minute to z" (convention says that
+ this should read "If z<32.." but there are some composers out there
+ that defy conventions). Default values are 6 ticks/division, and
+ 125 beats/minute (4 divisions = 1 beat). The beats/minute tag is
+ only meaningful for 6 ticks/division. To get a more accurate view
+ of how things work, use the following formula:
+ 24 * beats/minute
+ divisions/minute = -----------------
+ ticks/division
+ Hence divisions/minute range from 24.75 to 6120, eg. to get a value
+ of 2000 divisions/minute use 3 ticks/division and 250 beats/minute.
+ If multiple "set speed" effects are performed in a single division,
+ the ones on higher-numbered channels take precedence over the ones
+ on lower-numbered channels. This effect has a large number of
+ different implementations, but the one described here has the
+ widest usage.
+ */
+
+ if( (effect&0xFF) < 0x21 )
+ {
+ if( effect&0xFF )
+ {
+ mod->song.speed = effect&0xFF;
+ mod->patternticksaim = (long)mod->song.speed * ((mod->playrate * 5 ) / (((long)2 * (long)mod->bpm)));
+ }
+ }
+
+ if( (effect&0xFF) >= 0x21 )
+ {
+ /// HZ = 2 * BPM / 5
+ mod->bpm = effect&0xFF;
+ mod->patternticksaim = (long)mod->song.speed * ((mod->playrate * 5 ) / (((long)2 * (long)mod->bpm)));
+ }
+
+ break;
+
+ default:
+ // Unsupported effect
+ break;
+
+ }
+
+}
+
+static void workeffect( note * nptr, channel * cptr )
+{
+ switch(cptr->effect)
+ {
+ case EFFECT_ARPEGGIO:
+
+ if( cptr->parameffect )
+ {
+ cptr->decalperiod = cptr->period - cptr->Arpperiods[cptr->ArpIndex];
+
+ cptr->ArpIndex++;
+ if( cptr->ArpIndex>2 )
+ cptr->ArpIndex = 0;
+ }
+ break;
+
+ case EFFECT_PORTAMENTO_UP:
+
+ if(cptr->period)
+ {
+ cptr->period -= cptr->parameffect;
+
+ if( cptr->period < 113 || cptr->period > 20000 )
+ cptr->period = 113;
+ }
+
+ break;
+
+ case EFFECT_PORTAMENTO_DOWN:
+
+ if(cptr->period)
+ {
+ cptr->period += cptr->parameffect;
+
+ if( cptr->period > 20000 )
+ cptr->period = 20000;
+ }
+
+ break;
+
+ case EFFECT_VOLSLIDE_TONEPORTA:
+ case EFFECT_TONE_PORTAMENTO:
+
+ if( cptr->period && ( cptr->period != cptr->portaperiod ) && cptr->portaperiod )
+ {
+ if( cptr->period > cptr->portaperiod )
+ {
+ if( cptr->period - cptr->portaperiod >= cptr->portaspeed )
+ {
+ cptr->period -= cptr->portaspeed;
+ }
+ else
+ {
+ cptr->period = cptr->portaperiod;
+ }
+ }
+ else
+ {
+ if( cptr->portaperiod - cptr->period >= cptr->portaspeed )
+ {
+ cptr->period += cptr->portaspeed;
+ }
+ else
+ {
+ cptr->period = cptr->portaperiod;
+ }
+ }
+
+ if( cptr->period == cptr->portaperiod )
+ {
+ // If the slide is over, don't let it to be retriggered.
+ cptr->portaperiod = 0;
+ }
+ }
+
+ if( cptr->effect == EFFECT_VOLSLIDE_TONEPORTA )
+ {
+ if( cptr->volumeslide > 0x0F )
+ {
+ cptr->volume = cptr->volume + (cptr->volumeslide>>4);
+
+ if(cptr->volume>63)
+ cptr->volume = 63;
+ }
+ else
+ {
+ cptr->volume = cptr->volume - (cptr->volumeslide);
+
+ if(cptr->volume>63)
+ cptr->volume=0;
+ }
+ }
+ break;
+
+ case EFFECT_VOLSLIDE_VIBRATO:
+ case EFFECT_VIBRATO:
+
+ cptr->vibraperiod = ( (cptr->vibraparam&0xF) * sintable[cptr->vibrapointeur&0x1F] )>>7;
+
+ if( cptr->vibrapointeur > 31 )
+ cptr->vibraperiod = -cptr->vibraperiod;
+
+ cptr->vibrapointeur = (cptr->vibrapointeur+(((cptr->vibraparam>>4))&0xf)) & 0x3F;
+
+ if( cptr->effect == EFFECT_VOLSLIDE_VIBRATO )
+ {
+ if( cptr->volumeslide > 0xF )
+ {
+ cptr->volume = cptr->volume+(cptr->volumeslide>>4);
+
+ if( cptr->volume > 64 )
+ cptr->volume = 64;
+ }
+ else
+ {
+ cptr->volume = cptr->volume - cptr->volumeslide;
+
+ if( cptr->volume > 64 )
+ cptr->volume = 0;
+ }
+ }
+
+ break;
+
+ case EFFECT_VOLUME_SLIDE:
+
+ if( cptr->volumeslide > 0xF )
+ {
+ cptr->volume += (cptr->volumeslide>>4);
+
+ if( cptr->volume > 64 )
+ cptr->volume = 64;
+ }
+ else
+ {
+ cptr->volume -= (cptr->volumeslide&0xf);
+
+ if( cptr->volume > 64 )
+ cptr->volume = 0;
+ }
+ break;
+
+ case EFFECT_E_NOTE_CUT:
+ if(cptr->cut_param)
+ cptr->cut_param--;
+
+ if(!cptr->cut_param)
+ cptr->volume = 0;
+ break;
+
+ default:
+ break;
+
+ }
+
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+bool jar_mod_init(jar_mod_context_t * modctx)
+{
+ muint i,j;
+
+ if( modctx )
+ {
+ memclear(modctx, 0, sizeof(jar_mod_context_t));
+ modctx->playrate = DEFAULT_SAMPLE_RATE;
+ modctx->stereo = 1;
+ modctx->stereo_separation = 1;
+ modctx->bits = 16;
+ modctx->filter = 1;
+
+ for(i=0; i < PERIOD_TABLE_LENGTH - 1; i++)
+ {
+ for(j=0; j < 8; j++)
+ {
+ modctx->fullperiod[(i*8) + j] = periodtable[i] - ((( periodtable[i] - periodtable[i+1] ) / 8) * j);
+ }
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+bool jar_mod_setcfg(jar_mod_context_t * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter)
+{
+ if( modctx )
+ {
+ modctx->playrate = samplerate;
+
+ if( stereo )
+ modctx->stereo = 1;
+ else
+ modctx->stereo = 0;
+
+ if(stereo_separation < 4)
+ {
+ modctx->stereo_separation = stereo_separation;
+ }
+
+ if( bits == 8 || bits == 16 )
+ modctx->bits = bits;
+ else
+ modctx->bits = 16;
+
+ if( filter )
+ modctx->filter = 1;
+ else
+ modctx->filter = 0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+// make certain that mod_data stays in memory while playing
+static bool jar_mod_load( jar_mod_context_t * modctx, void * mod_data, int mod_data_size )
+{
+ muint i, max;
+ unsigned short t;
+ sample *sptr;
+ unsigned char * modmemory,* endmodmemory;
+
+ modmemory = (unsigned char *)mod_data;
+ endmodmemory = modmemory + mod_data_size;
+
+
+
+ if(modmemory)
+ {
+ if( modctx )
+ {
+ memcopy(&(modctx->song.title),modmemory,1084);
+
+ i = 0;
+ modctx->number_of_channels = 0;
+ while(modlist[i].numberofchannels)
+ {
+ if(memcompare(modctx->song.signature,modlist[i].signature,4))
+ {
+ modctx->number_of_channels = modlist[i].numberofchannels;
+ }
+
+ i++;
+ }
+
+ if( !modctx->number_of_channels )
+ {
+ // 15 Samples modules support
+ // Shift the whole datas to make it look likes a standard 4 channels mod.
+ memcopy(&(modctx->song.signature), "M.K.", 4);
+ memcopy(&(modctx->song.length), &(modctx->song.samples[15]), 130);
+ memclear(&(modctx->song.samples[15]), 0, 480);
+ modmemory += 600;
+ modctx->number_of_channels = 4;
+ }
+ else
+ {
+ modmemory += 1084;
+ }
+
+ if( modmemory >= endmodmemory )
+ return 0; // End passed ? - Probably a bad file !
+
+ // Patterns loading
+ for (i = max = 0; i < 128; i++)
+ {
+ while (max <= modctx->song.patterntable[i])
+ {
+ modctx->patterndata[max] = (note*)modmemory;
+ modmemory += (256*modctx->number_of_channels);
+ max++;
+
+ if( modmemory >= endmodmemory )
+ return 0; // End passed ? - Probably a bad file !
+ }
+ }
+
+ for (i = 0; i < 31; i++)
+ modctx->sampledata[i]=0;
+
+ // Samples loading
+ for (i = 0, sptr = modctx->song.samples; i <31; i++, sptr++)
+ {
+ t= (sptr->length &0xFF00)>>8 | (sptr->length &0xFF)<<8;
+ sptr->length = t*2;
+
+ t= (sptr->reppnt &0xFF00)>>8 | (sptr->reppnt &0xFF)<<8;
+ sptr->reppnt = t*2;
+
+ t= (sptr->replen &0xFF00)>>8 | (sptr->replen &0xFF)<<8;
+ sptr->replen = t*2;
+
+
+ if (sptr->length == 0) continue;
+
+ modctx->sampledata[i] = (char*)modmemory;
+ modmemory += sptr->length;
+
+ if (sptr->replen + sptr->reppnt > sptr->length)
+ sptr->replen = sptr->length - sptr->reppnt;
+
+ if( modmemory > endmodmemory )
+ return 0; // End passed ? - Probably a bad file !
+ }
+
+ // States init
+
+ modctx->tablepos = 0;
+ modctx->patternpos = 0;
+ modctx->song.speed = 6;
+ modctx->bpm = 125;
+ modctx->samplenb = 0;
+
+ modctx->patternticks = (((long)modctx->song.speed * modctx->playrate * 5)/ (2 * modctx->bpm)) + 1;
+ modctx->patternticksaim = ((long)modctx->song.speed * modctx->playrate * 5) / (2 * modctx->bpm);
+
+ modctx->sampleticksconst = 3546894UL / modctx->playrate; //8448*428/playrate;
+
+ for(i=0; i < modctx->number_of_channels; i++)
+ {
+ modctx->channels[i].volume = 0;
+ modctx->channels[i].period = 0;
+ }
+
+ modctx->mod_loaded = 1;
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void jar_mod_fillbuffer( jar_mod_context_t * modctx, short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf )
+{
+ unsigned long i, j;
+ unsigned long k;
+ unsigned char c;
+ unsigned int state_remaining_steps;
+ int l,r;
+ int ll,lr;
+ int tl,tr;
+ short finalperiod;
+ note *nptr;
+ channel *cptr;
+
+ if( modctx && outbuffer )
+ {
+ if(modctx->mod_loaded)
+ {
+ state_remaining_steps = 0;
+
+ if( trkbuf )
+ {
+ trkbuf->cur_rd_index = 0;
+
+ memcopy(trkbuf->name,modctx->song.title,sizeof(modctx->song.title));
+
+ for(i=0;i<31;i++)
+ {
+ memcopy(trkbuf->instruments[i].name,modctx->song.samples[i].name,sizeof(trkbuf->instruments[i].name));
+ }
+ }
+
+ ll = modctx->last_l_sample;
+ lr = modctx->last_r_sample;
+
+ for (i = 0; i < nbsample; i++)
+ {
+ //---------------------------------------
+ if( modctx->patternticks++ > modctx->patternticksaim )
+ {
+ if( !modctx->patterndelay )
+ {
+ nptr = modctx->patterndata[modctx->song.patterntable[modctx->tablepos]];
+ nptr = nptr + modctx->patternpos;
+ cptr = modctx->channels;
+
+ modctx->patternticks = 0;
+ modctx->patterntickse = 0;
+
+ for(c=0;c<modctx->number_of_channels;c++)
+ {
+ worknote((note*)(nptr+c), (channel*)(cptr+c),(char)(c+1),modctx);
+ }
+
+ if( !modctx->jump_loop_effect )
+ modctx->patternpos += modctx->number_of_channels;
+ else
+ modctx->jump_loop_effect = 0;
+
+ if( modctx->patternpos == 64*modctx->number_of_channels )
+ {
+ modctx->tablepos++;
+ modctx->patternpos = 0;
+ if(modctx->tablepos >= modctx->song.length)
+ {
+ modctx->tablepos = 0;
+ modctx->loopcount++; // count next loop
+ }
+ }
+ }
+ else
+ {
+ modctx->patterndelay--;
+ modctx->patternticks = 0;
+ modctx->patterntickse = 0;
+ }
+
+ }
+
+ if( modctx->patterntickse++ > (modctx->patternticksaim/modctx->song.speed) )
+ {
+ nptr = modctx->patterndata[modctx->song.patterntable[modctx->tablepos]];
+ nptr = nptr + modctx->patternpos;
+ cptr = modctx->channels;
+
+ for(c=0;c<modctx->number_of_channels;c++)
+ {
+ workeffect(nptr+c, cptr+c);
+ }
+
+ modctx->patterntickse = 0;
+ }
+
+ //---------------------------------------
+
+ if( trkbuf && !state_remaining_steps )
+ {
+ if( trkbuf->nb_of_state < trkbuf->nb_max_of_state )
+ {
+ memclear(&trkbuf->track_state_buf[trkbuf->nb_of_state], 0, sizeof(tracker_state));
+ }
+ }
+
+ l=0;
+ r=0;
+
+ for(j =0, cptr = modctx->channels; j < modctx->number_of_channels ; j++, cptr++)
+ {
+ if( cptr->period != 0 )
+ {
+ finalperiod = cptr->period - cptr->decalperiod - cptr->vibraperiod;
+ if( finalperiod )
+ {
+ cptr->samppos += ( (modctx->sampleticksconst<<10) / finalperiod );
+ }
+
+ cptr->ticks++;
+
+ if( cptr->replen<=2 )
+ {
+ if( (cptr->samppos>>10) >= (cptr->length) )
+ {
+ cptr->length = 0;
+ cptr->reppnt = 0;
+
+ if( cptr->length )
+ cptr->samppos = cptr->samppos % (((unsigned long)cptr->length)<<10);
+ else
+ cptr->samppos = 0;
+ }
+ }
+ else
+ {
+ if( (cptr->samppos>>10) >= (unsigned long)(cptr->replen+cptr->reppnt) )
+ {
+ cptr->samppos = ((unsigned long)(cptr->reppnt)<<10) + (cptr->samppos % ((unsigned long)(cptr->replen+cptr->reppnt)<<10));
+ }
+ }
+
+ k = cptr->samppos >> 10;
+
+ if( cptr->sampdata!=0 && ( ((j&3)==1) || ((j&3)==2) ) )
+ {
+ r += ( cptr->sampdata[k] * cptr->volume );
+ }
+
+ if( cptr->sampdata!=0 && ( ((j&3)==0) || ((j&3)==3) ) )
+ {
+ l += ( cptr->sampdata[k] * cptr->volume );
+ }
+
+ if( trkbuf && !state_remaining_steps )
+ {
+ if( trkbuf->nb_of_state < trkbuf->nb_max_of_state )
+ {
+ trkbuf->track_state_buf[trkbuf->nb_of_state].number_of_tracks = modctx->number_of_channels;
+ trkbuf->track_state_buf[trkbuf->nb_of_state].buf_index = i;
+ trkbuf->track_state_buf[trkbuf->nb_of_state].cur_pattern = modctx->song.patterntable[modctx->tablepos];
+ trkbuf->track_state_buf[trkbuf->nb_of_state].cur_pattern_pos = modctx->patternpos / modctx->number_of_channels;
+ trkbuf->track_state_buf[trkbuf->nb_of_state].cur_pattern_table_pos = modctx->tablepos;
+ trkbuf->track_state_buf[trkbuf->nb_of_state].bpm = modctx->bpm;
+ trkbuf->track_state_buf[trkbuf->nb_of_state].speed = modctx->song.speed;
+ trkbuf->track_state_buf[trkbuf->nb_of_state].tracks[j].cur_effect = cptr->effect_code;
+ trkbuf->track_state_buf[trkbuf->nb_of_state].tracks[j].cur_parameffect = cptr->parameffect;
+ trkbuf->track_state_buf[trkbuf->nb_of_state].tracks[j].cur_period = finalperiod;
+ trkbuf->track_state_buf[trkbuf->nb_of_state].tracks[j].cur_volume = cptr->volume;
+ trkbuf->track_state_buf[trkbuf->nb_of_state].tracks[j].instrument_number = (unsigned char)cptr->sampnum;
+ }
+ }
+ }
+ }
+
+ if( trkbuf && !state_remaining_steps )
+ {
+ state_remaining_steps = trkbuf->sample_step;
+
+ if(trkbuf->nb_of_state < trkbuf->nb_max_of_state)
+ trkbuf->nb_of_state++;
+ }
+ else
+ {
+ state_remaining_steps--;
+ }
+
+ tl = (short)l;
+ tr = (short)r;
+
+ if ( modctx->filter )
+ {
+ // Filter
+ l = (l+ll)>>1;
+ r = (r+lr)>>1;
+ }
+
+ if ( modctx->stereo_separation == 1 )
+ {
+ // Left & Right Stereo panning
+ l = (l+(r>>1));
+ r = (r+(l>>1));
+ }
+
+ // Level limitation
+ if( l > 32767 ) l = 32767;
+ if( l < -32768 ) l = -32768;
+ if( r > 32767 ) r = 32767;
+ if( r < -32768 ) r = -32768;
+
+ // Store the final sample.
+ outbuffer[(i*2)] = l;
+ outbuffer[(i*2)+1] = r;
+
+ ll = tl;
+ lr = tr;
+
+ }
+
+ modctx->last_l_sample = ll;
+ modctx->last_r_sample = lr;
+
+ modctx->samplenb = modctx->samplenb+nbsample;
+ }
+ else
+ {
+ for (i = 0; i < nbsample; i++)
+ {
+ // Mod not loaded. Return blank buffer.
+ outbuffer[(i*2)] = 0;
+ outbuffer[(i*2)+1] = 0;
+ }
+
+ if(trkbuf)
+ {
+ trkbuf->nb_of_state = 0;
+ trkbuf->cur_rd_index = 0;
+ trkbuf->name[0] = 0;
+ memclear(trkbuf->track_state_buf, 0, sizeof(tracker_state) * trkbuf->nb_max_of_state);
+ memclear(trkbuf->instruments, 0, sizeof(trkbuf->instruments));
+ }
+ }
+ }
+}
+
+//resets internals for mod context
+static bool jar_mod_reset( jar_mod_context_t * modctx)
+{
+ if(modctx)
+ {
+ memclear(&modctx->song, 0, sizeof(modctx->song));
+ memclear(&modctx->sampledata, 0, sizeof(modctx->sampledata));
+ memclear(&modctx->patterndata, 0, sizeof(modctx->patterndata));
+ modctx->tablepos = 0;
+ modctx->patternpos = 0;
+ modctx->patterndelay = 0;
+ modctx->jump_loop_effect = 0;
+ modctx->bpm = 0;
+ modctx->patternticks = 0;
+ modctx->patterntickse = 0;
+ modctx->patternticksaim = 0;
+ modctx->sampleticksconst = 0;
+ modctx->samplenb = 0;
+ memclear(modctx->channels, 0, sizeof(modctx->channels));
+ modctx->number_of_channels = 0;
+ modctx->mod_loaded = 0;
+ modctx->last_r_sample = 0;
+ modctx->last_l_sample = 0;
+
+ return jar_mod_init(modctx);
+ }
+ return 0;
+}
+
+void jar_mod_unload( jar_mod_context_t * modctx)
+{
+ if(modctx)
+ {
+ if(modctx->modfile)
+ {
+ free(modctx->modfile);
+ modctx->modfile = 0;
+ modctx->modfilesize = 0;
+ modctx->loopcount = 0;
+ }
+ jar_mod_reset(modctx);
+ }
+}
+
+
+
+mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename)
+{
+ mulong fsize = 0;
+ if(modctx->modfile)
+ {
+ free(modctx->modfile);
+ modctx->modfile = 0;
+ }
+
+ FILE *f = fopen(filename, "rb");
+ if(f)
+ {
+ fseek(f,0,SEEK_END);
+ fsize = ftell(f);
+ fseek(f,0,SEEK_SET);
+
+ if(fsize && fsize < 32*1024*1024)
+ {
+ modctx->modfile = malloc(fsize);
+ modctx->modfilesize = fsize;
+ memset(modctx->modfile, 0, fsize);
+ fread(modctx->modfile, fsize, 1, f);
+ fclose(f);
+
+ if(!jar_mod_load(modctx, (void*)modctx->modfile, fsize)) fsize = 0;
+ } else fsize = 0;
+ }
+ return fsize;
+}
+
+mulong jar_mod_current_samples(jar_mod_context_t * modctx)
+{
+ if(modctx)
+ return modctx->samplenb;
+
+ return 0;
+}
+
+// Works, however it is very slow, this data should be cached to ensure it is run only once per file
+mulong jar_mod_max_samples(jar_mod_context_t * ctx)
+{
+ mint buff[2];
+ mulong len;
+ mulong lastcount = ctx->loopcount;
+
+ while(ctx->loopcount <= lastcount)
+ jar_mod_fillbuffer(ctx, buff, 1, 0);
+
+ len = ctx->samplenb;
+ jar_mod_seek_start(ctx);
+
+ return len;
+}
+
+// move seek_val to sample index, 0 -> jar_mod_max_samples is the range
+void jar_mod_seek_start(jar_mod_context_t * ctx)
+{
+ if(ctx && ctx->modfile)
+ {
+ muchar* ftmp = ctx->modfile;
+ mulong stmp = ctx->modfilesize;
+ muint lcnt = ctx->loopcount;
+
+ if(jar_mod_reset(ctx)){
+ jar_mod_load(ctx, ftmp, stmp);
+ ctx->modfile = ftmp;
+ ctx->modfilesize = stmp;
+ ctx->loopcount = lcnt;
+ }
+ }
+}
+
+#endif // end of JAR_MOD_IMPLEMENTATION
+//-------------------------------------------------------------------------------
+
+
+#endif //end of header file \ No newline at end of file
diff --git a/src/external/jar_xm.h b/src/external/jar_xm.h
new file mode 100644
index 00000000..7f0517df
--- /dev/null
+++ b/src/external/jar_xm.h
@@ -0,0 +1,2664 @@
+// jar_xm.h - v0.01 - public domain - Joshua Reisenauer, MAR 2016
+//
+// HISTORY:
+//
+// v0.01 2016-02-22 Setup
+//
+//
+// USAGE:
+//
+// In ONE source file, put:
+//
+// #define JAR_XM_IMPLEMENTATION
+// #include "jar_xm.h"
+//
+// Other source files should just include jar_xm.h
+//
+// SAMPLE CODE:
+//
+// jar_xm_context_t *musicptr;
+// float musicBuffer[48000 / 60];
+// int intro_load(void)
+// {
+// jar_xm_create_context_from_file(&musicptr, 48000, "Song.XM");
+// return 1;
+// }
+// int intro_unload(void)
+// {
+// jar_xm_free_context(musicptr);
+// return 1;
+// }
+// int intro_tick(long counter)
+// {
+// jar_xm_generate_samples(musicptr, musicBuffer, (48000 / 60) / 2);
+// if(IsKeyDown(KEY_ENTER))
+// return 1;
+// return 0;
+// }
+//
+//
+// LISCENSE - FOR LIBXM:
+//
+// Author: Romain "Artefact2" Dalmaso <artefact2@gmail.com>
+// Contributor: Dan Spencer <dan@atomicpotato.net>
+// Repackaged into jar_xm.h By: Joshua Adam Reisenauer <kd7tck@gmail.com>
+// This program is free software. It comes without any warranty, to the
+// extent permitted by applicable law. You can redistribute it and/or
+// modify it under the terms of the Do What The Fuck You Want To Public
+// License, Version 2, as published by Sam Hocevar. See
+// http://sam.zoy.org/wtfpl/COPYING for more details.
+
+#ifndef INCLUDE_JAR_XM_H
+#define INCLUDE_JAR_XM_H
+
+#define JAR_XM_DEBUG 0
+#define JAR_XM_LINEAR_INTERPOLATION 1 // speed increase with decrease in quality
+#define JAR_XM_DEFENSIVE 1
+#define JAR_XM_RAMPING 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include <string.h>
+
+
+
+//-------------------------------------------------------------------------------
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct jar_xm_context_s;
+typedef struct jar_xm_context_s jar_xm_context_t;
+
+/** Create a XM context.
+ *
+ * @param moddata the contents of the module
+ * @param rate play rate in Hz, recommended value of 48000
+ *
+ * @returns 0 on success
+ * @returns 1 if module data is not sane
+ * @returns 2 if memory allocation failed
+ * @returns 3 unable to open input file
+ * @returns 4 fseek() failed
+ * @returns 5 fread() failed
+ * @returns 6 unkown error
+ *
+ * @deprecated This function is unsafe!
+ * @see jar_xm_create_context_safe()
+ */
+int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const char* filename);
+
+/** Create a XM context.
+ *
+ * @param moddata the contents of the module
+ * @param rate play rate in Hz, recommended value of 48000
+ *
+ * @returns 0 on success
+ * @returns 1 if module data is not sane
+ * @returns 2 if memory allocation failed
+ *
+ * @deprecated This function is unsafe!
+ * @see jar_xm_create_context_safe()
+ */
+int jar_xm_create_context(jar_xm_context_t** ctx, const char* moddata, uint32_t rate);
+
+/** Create a XM context.
+ *
+ * @param moddata the contents of the module
+ * @param moddata_length the length of the contents of the module, in bytes
+ * @param rate play rate in Hz, recommended value of 48000
+ *
+ * @returns 0 on success
+ * @returns 1 if module data is not sane
+ * @returns 2 if memory allocation failed
+ */
+int jar_xm_create_context_safe(jar_xm_context_t** ctx, const char* moddata, size_t moddata_length, uint32_t rate);
+
+/** Free a XM context created by jar_xm_create_context(). */
+void jar_xm_free_context(jar_xm_context_t* ctx);
+
+/** Play the module and put the sound samples in an output buffer.
+ *
+ * @param output buffer of 2*numsamples elements (A left and right value for each sample)
+ * @param numsamples number of samples to generate
+ */
+void jar_xm_generate_samples(jar_xm_context_t* ctx, float* output, size_t numsamples);
+
+/** Play the module, resample from 32 bit to 16 bit, and put the sound samples in an output buffer.
+ *
+ * @param output buffer of 2*numsamples elements (A left and right value for each sample)
+ * @param numsamples number of samples to generate
+ */
+void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t numsamples)
+{
+ float* musicBuffer = malloc((2*numsamples)*sizeof(float));
+ jar_xm_generate_samples(ctx, musicBuffer, numsamples);
+
+ if(output){
+ int x;
+ for(x=0;x<2*numsamples;x++)
+ output[x] = musicBuffer[x] * SHRT_MAX;
+ }
+
+ free(musicBuffer);
+}
+
+/** Play the module, resample from 32 bit to 8 bit, and put the sound samples in an output buffer.
+ *
+ * @param output buffer of 2*numsamples elements (A left and right value for each sample)
+ * @param numsamples number of samples to generate
+ */
+void jar_xm_generate_samples_8bit(jar_xm_context_t* ctx, char* output, size_t numsamples)
+{
+ float* musicBuffer = malloc((2*numsamples)*sizeof(float));
+ jar_xm_generate_samples(ctx, musicBuffer, numsamples);
+
+ if(output){
+ int x;
+ for(x=0;x<2*numsamples;x++)
+ output[x] = musicBuffer[x] * CHAR_MAX;
+ }
+
+ free(musicBuffer);
+}
+
+
+
+/** Set the maximum number of times a module can loop. After the
+ * specified number of loops, calls to jar_xm_generate_samples will only
+ * generate silence. You can control the current number of loops with
+ * jar_xm_get_loop_count().
+ *
+ * @param loopcnt maximum number of loops. Use 0 to loop
+ * indefinitely. */
+void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt);
+
+/** Get the loop count of the currently playing module. This value is
+ * 0 when the module is still playing, 1 when the module has looped
+ * once, etc. */
+uint8_t jar_xm_get_loop_count(jar_xm_context_t* ctx);
+
+
+
+/** Mute or unmute a channel.
+ *
+ * @note Channel numbers go from 1 to jar_xm_get_number_of_channels(...).
+ *
+ * @return whether the channel was muted.
+ */
+bool jar_xm_mute_channel(jar_xm_context_t* ctx, uint16_t, bool);
+
+/** Mute or unmute an instrument.
+ *
+ * @note Instrument numbers go from 1 to
+ * jar_xm_get_number_of_instruments(...).
+ *
+ * @return whether the instrument was muted.
+ */
+bool jar_xm_mute_instrument(jar_xm_context_t* ctx, uint16_t, bool);
+
+
+
+/** Get the module name as a NUL-terminated string. */
+const char* jar_xm_get_module_name(jar_xm_context_t* ctx);
+
+/** Get the tracker name as a NUL-terminated string. */
+const char* jar_xm_get_tracker_name(jar_xm_context_t* ctx);
+
+
+
+/** Get the number of channels. */
+uint16_t jar_xm_get_number_of_channels(jar_xm_context_t* ctx);
+
+/** Get the module length (in patterns). */
+uint16_t jar_xm_get_module_length(jar_xm_context_t*);
+
+/** Get the number of patterns. */
+uint16_t jar_xm_get_number_of_patterns(jar_xm_context_t* ctx);
+
+/** Get the number of rows of a pattern.
+ *
+ * @note Pattern numbers go from 0 to
+ * jar_xm_get_number_of_patterns(...)-1.
+ */
+uint16_t jar_xm_get_number_of_rows(jar_xm_context_t* ctx, uint16_t);
+
+/** Get the number of instruments. */
+uint16_t jar_xm_get_number_of_instruments(jar_xm_context_t* ctx);
+
+/** Get the number of samples of an instrument.
+ *
+ * @note Instrument numbers go from 1 to
+ * jar_xm_get_number_of_instruments(...).
+ */
+uint16_t jar_xm_get_number_of_samples(jar_xm_context_t* ctx, uint16_t);
+
+
+
+/** Get the current module speed.
+ *
+ * @param bpm will receive the current BPM
+ * @param tempo will receive the current tempo (ticks per line)
+ */
+void jar_xm_get_playing_speed(jar_xm_context_t* ctx, uint16_t* bpm, uint16_t* tempo);
+
+/** Get the current position in the module being played.
+ *
+ * @param pattern_index if not NULL, will receive the current pattern
+ * index in the POT (pattern order table)
+ *
+ * @param pattern if not NULL, will receive the current pattern number
+ *
+ * @param row if not NULL, will receive the current row
+ *
+ * @param samples if not NULL, will receive the total number of
+ * generated samples (divide by sample rate to get seconds of
+ * generated audio)
+ */
+void jar_xm_get_position(jar_xm_context_t* ctx, uint8_t* pattern_index, uint8_t* pattern, uint8_t* row, uint64_t* samples);
+
+/** Get the latest time (in number of generated samples) when a
+ * particular instrument was triggered in any channel.
+ *
+ * @note Instrument numbers go from 1 to
+ * jar_xm_get_number_of_instruments(...).
+ */
+uint64_t jar_xm_get_latest_trigger_of_instrument(jar_xm_context_t* ctx, uint16_t);
+
+/** Get the latest time (in number of generated samples) when a
+ * particular sample was triggered in any channel.
+ *
+ * @note Instrument numbers go from 1 to
+ * jar_xm_get_number_of_instruments(...).
+ *
+ * @note Sample numbers go from 0 to
+ * jar_xm_get_nubmer_of_samples(...,instr)-1.
+ */
+uint64_t jar_xm_get_latest_trigger_of_sample(jar_xm_context_t* ctx, uint16_t instr, uint16_t sample);
+
+/** Get the latest time (in number of generated samples) when any
+ * instrument was triggered in a given channel.
+ *
+ * @note Channel numbers go from 1 to jar_xm_get_number_of_channels(...).
+ */
+uint64_t jar_xm_get_latest_trigger_of_channel(jar_xm_context_t* ctx, uint16_t);
+
+/** Get the number of remaining samples. Divide by 2 to get the number of individual LR data samples.
+ *
+ * @note This is the remaining number of samples before the loop starts module again, or halts if on last pass.
+ * @note This function is very slow and should only be run once, if at all.
+ */
+uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx);
+
+#ifdef __cplusplus
+}
+#endif
+//-------------------------------------------------------------------------------
+
+
+
+
+
+
+//Function Definitions-----------------------------------------------------------
+#ifdef JAR_XM_IMPLEMENTATION
+
+#include <math.h>
+#include <string.h>
+
+#ifdef JAR_XM_DEBUG
+#include <stdio.h>
+#define DEBUG(fmt, ...) do { \
+ fprintf(stderr, "%s(): " fmt "\n", __func__, __VA_ARGS__); \
+ fflush(stderr); \
+ } while(0)
+#else
+#define DEBUG(...)
+#endif
+
+#if jar_xm_BIG_ENDIAN
+#error "Big endian platforms are not yet supported, sorry"
+/* Make sure the compiler stops, even if #error is ignored */
+extern int __fail[-1];
+#endif
+
+/* ----- XM constants ----- */
+
+#define SAMPLE_NAME_LENGTH 22
+#define INSTRUMENT_NAME_LENGTH 22
+#define MODULE_NAME_LENGTH 20
+#define TRACKER_NAME_LENGTH 20
+#define PATTERN_ORDER_TABLE_LENGTH 256
+#define NUM_NOTES 96
+#define NUM_ENVELOPE_POINTS 12
+#define MAX_NUM_ROWS 256
+
+#if JAR_XM_RAMPING
+#define jar_xm_SAMPLE_RAMPING_POINTS 0x20
+#endif
+
+/* ----- Data types ----- */
+
+enum jar_xm_waveform_type_e {
+ jar_xm_SINE_WAVEFORM = 0,
+ jar_xm_RAMP_DOWN_WAVEFORM = 1,
+ jar_xm_SQUARE_WAVEFORM = 2,
+ jar_xm_RANDOM_WAVEFORM = 3,
+ jar_xm_RAMP_UP_WAVEFORM = 4,
+};
+typedef enum jar_xm_waveform_type_e jar_xm_waveform_type_t;
+
+enum jar_xm_loop_type_e {
+ jar_xm_NO_LOOP,
+ jar_xm_FORWARD_LOOP,
+ jar_xm_PING_PONG_LOOP,
+};
+typedef enum jar_xm_loop_type_e jar_xm_loop_type_t;
+
+enum jar_xm_frequency_type_e {
+ jar_xm_LINEAR_FREQUENCIES,
+ jar_xm_AMIGA_FREQUENCIES,
+};
+typedef enum jar_xm_frequency_type_e jar_xm_frequency_type_t;
+
+struct jar_xm_envelope_point_s {
+ uint16_t frame;
+ uint16_t value;
+};
+typedef struct jar_xm_envelope_point_s jar_xm_envelope_point_t;
+
+struct jar_xm_envelope_s {
+ jar_xm_envelope_point_t points[NUM_ENVELOPE_POINTS];
+ uint8_t num_points;
+ uint8_t sustain_point;
+ uint8_t loop_start_point;
+ uint8_t loop_end_point;
+ bool enabled;
+ bool sustain_enabled;
+ bool loop_enabled;
+};
+typedef struct jar_xm_envelope_s jar_xm_envelope_t;
+
+struct jar_xm_sample_s {
+ char name[SAMPLE_NAME_LENGTH + 1];
+ int8_t bits; /* Either 8 or 16 */
+
+ uint32_t length;
+ uint32_t loop_start;
+ uint32_t loop_length;
+ uint32_t loop_end;
+ float volume;
+ int8_t finetune;
+ jar_xm_loop_type_t loop_type;
+ float panning;
+ int8_t relative_note;
+ uint64_t latest_trigger;
+
+ float* data;
+ };
+ typedef struct jar_xm_sample_s jar_xm_sample_t;
+
+ struct jar_xm_instrument_s {
+ char name[INSTRUMENT_NAME_LENGTH + 1];
+ uint16_t num_samples;
+ uint8_t sample_of_notes[NUM_NOTES];
+ jar_xm_envelope_t volume_envelope;
+ jar_xm_envelope_t panning_envelope;
+ jar_xm_waveform_type_t vibrato_type;
+ uint8_t vibrato_sweep;
+ uint8_t vibrato_depth;
+ uint8_t vibrato_rate;
+ uint16_t volume_fadeout;
+ uint64_t latest_trigger;
+ bool muted;
+
+ jar_xm_sample_t* samples;
+ };
+ typedef struct jar_xm_instrument_s jar_xm_instrument_t;
+
+ struct jar_xm_pattern_slot_s {
+ uint8_t note; /* 1-96, 97 = Key Off note */
+ uint8_t instrument; /* 1-128 */
+ uint8_t volume_column;
+ uint8_t effect_type;
+ uint8_t effect_param;
+ };
+ typedef struct jar_xm_pattern_slot_s jar_xm_pattern_slot_t;
+
+ struct jar_xm_pattern_s {
+ uint16_t num_rows;
+ jar_xm_pattern_slot_t* slots; /* Array of size num_rows * num_channels */
+ };
+ typedef struct jar_xm_pattern_s jar_xm_pattern_t;
+
+ struct jar_xm_module_s {
+ char name[MODULE_NAME_LENGTH + 1];
+ char trackername[TRACKER_NAME_LENGTH + 1];
+ uint16_t length;
+ uint16_t restart_position;
+ uint16_t num_channels;
+ uint16_t num_patterns;
+ uint16_t num_instruments;
+ jar_xm_frequency_type_t frequency_type;
+ uint8_t pattern_table[PATTERN_ORDER_TABLE_LENGTH];
+
+ jar_xm_pattern_t* patterns;
+ jar_xm_instrument_t* instruments; /* Instrument 1 has index 0,
+ * instrument 2 has index 1, etc. */
+ };
+ typedef struct jar_xm_module_s jar_xm_module_t;
+
+ struct jar_xm_channel_context_s {
+ float note;
+ float orig_note; /* The original note before effect modifications, as read in the pattern. */
+ jar_xm_instrument_t* instrument; /* Could be NULL */
+ jar_xm_sample_t* sample; /* Could be NULL */
+ jar_xm_pattern_slot_t* current;
+
+ float sample_position;
+ float period;
+ float frequency;
+ float step;
+ bool ping; /* For ping-pong samples: true is -->, false is <-- */
+
+ float volume; /* Ideally between 0 (muted) and 1 (loudest) */
+ float panning; /* Between 0 (left) and 1 (right); 0.5 is centered */
+
+ uint16_t autovibrato_ticks;
+
+ bool sustained;
+ float fadeout_volume;
+ float volume_envelope_volume;
+ float panning_envelope_panning;
+ uint16_t volume_envelope_frame_count;
+ uint16_t panning_envelope_frame_count;
+
+ float autovibrato_note_offset;
+
+ bool arp_in_progress;
+ uint8_t arp_note_offset;
+ uint8_t volume_slide_param;
+ uint8_t fine_volume_slide_param;
+ uint8_t global_volume_slide_param;
+ uint8_t panning_slide_param;
+ uint8_t portamento_up_param;
+ uint8_t portamento_down_param;
+ uint8_t fine_portamento_up_param;
+ uint8_t fine_portamento_down_param;
+ uint8_t extra_fine_portamento_up_param;
+ uint8_t extra_fine_portamento_down_param;
+ uint8_t tone_portamento_param;
+ float tone_portamento_target_period;
+ uint8_t multi_retrig_param;
+ uint8_t note_delay_param;
+ uint8_t pattern_loop_origin; /* Where to restart a E6y loop */
+ uint8_t pattern_loop_count; /* How many loop passes have been done */
+ bool vibrato_in_progress;
+ jar_xm_waveform_type_t vibrato_waveform;
+ bool vibrato_waveform_retrigger; /* True if a new note retriggers the waveform */
+ uint8_t vibrato_param;
+ uint16_t vibrato_ticks; /* Position in the waveform */
+ float vibrato_note_offset;
+ jar_xm_waveform_type_t tremolo_waveform;
+ bool tremolo_waveform_retrigger;
+ uint8_t tremolo_param;
+ uint8_t tremolo_ticks;
+ float tremolo_volume;
+ uint8_t tremor_param;
+ bool tremor_on;
+
+ uint64_t latest_trigger;
+ bool muted;
+
+#if JAR_XM_RAMPING
+ /* These values are updated at the end of each tick, to save
+ * a couple of float operations on every generated sample. */
+ float target_panning;
+ float target_volume;
+
+ unsigned long frame_count;
+ float end_of_previous_sample[jar_xm_SAMPLE_RAMPING_POINTS];
+#endif
+
+ float actual_panning;
+ float actual_volume;
+ };
+ typedef struct jar_xm_channel_context_s jar_xm_channel_context_t;
+
+ struct jar_xm_context_s {
+ void* allocated_memory;
+ jar_xm_module_t module;
+ uint32_t rate;
+
+ uint16_t tempo;
+ uint16_t bpm;
+ float global_volume;
+ float amplification;
+
+#if JAR_XM_RAMPING
+ /* How much is a channel final volume allowed to change per
+ * sample; this is used to avoid abrubt volume changes which
+ * manifest as "clicks" in the generated sound. */
+ float volume_ramp;
+ float panning_ramp; /* Same for panning. */
+#endif
+
+ uint8_t current_table_index;
+ uint8_t current_row;
+ uint16_t current_tick; /* Can go below 255, with high tempo and a pattern delay */
+ float remaining_samples_in_tick;
+ uint64_t generated_samples;
+
+ bool position_jump;
+ bool pattern_break;
+ uint8_t jump_dest;
+ uint8_t jump_row;
+
+ /* Extra ticks to be played before going to the next row -
+ * Used for EEy effect */
+ uint16_t extra_ticks;
+
+ uint8_t* row_loop_count; /* Array of size MAX_NUM_ROWS * module_length */
+ uint8_t loop_count;
+ uint8_t max_loop_count;
+
+ jar_xm_channel_context_t* channels;
+};
+
+/* ----- Internal API ----- */
+
+#if JAR_XM_DEFENSIVE
+
+/** Check the module data for errors/inconsistencies.
+ *
+ * @returns 0 if everything looks OK. Module should be safe to load.
+ */
+int jar_xm_check_sanity_preload(const char*, size_t);
+
+/** Check a loaded module for errors/inconsistencies.
+ *
+ * @returns 0 if everything looks OK.
+ */
+int jar_xm_check_sanity_postload(jar_xm_context_t*);
+
+#endif
+
+/** Get the number of bytes needed to store the module data in a
+ * dynamically allocated blank context.
+ *
+ * Things that are dynamically allocated:
+ * - sample data
+ * - sample structures in instruments
+ * - pattern data
+ * - row loop count arrays
+ * - pattern structures in module
+ * - instrument structures in module
+ * - channel contexts
+ * - context structure itself
+
+ * @returns 0 if everything looks OK.
+ */
+size_t jar_xm_get_memory_needed_for_context(const char*, size_t);
+
+/** Populate the context from module data.
+ *
+ * @returns pointer to the memory pool
+ */
+char* jar_xm_load_module(jar_xm_context_t*, const char*, size_t, char*);
+
+int jar_xm_create_context(jar_xm_context_t** ctxp, const char* moddata, uint32_t rate) {
+ return jar_xm_create_context_safe(ctxp, moddata, SIZE_MAX, rate);
+}
+
+int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, size_t moddata_length, uint32_t rate) {
+#if JAR_XM_DEFENSIVE
+ int ret;
+#endif
+ size_t bytes_needed;
+ char* mempool;
+ jar_xm_context_t* ctx;
+
+#if JAR_XM_DEFENSIVE
+ if((ret = jar_xm_check_sanity_preload(moddata, moddata_length))) {
+ DEBUG("jar_xm_check_sanity_preload() returned %i, module is not safe to load", ret);
+ return 1;
+ }
+#endif
+
+ bytes_needed = jar_xm_get_memory_needed_for_context(moddata, moddata_length);
+ mempool = malloc(bytes_needed);
+ if(mempool == NULL && bytes_needed > 0) {
+ /* malloc() failed, trouble ahead */
+ DEBUG("call to malloc() failed, returned %p", (void*)mempool);
+ return 2;
+ }
+
+ /* Initialize most of the fields to 0, 0.f, NULL or false depending on type */
+ memset(mempool, 0, bytes_needed);
+
+ ctx = (*ctxp = (jar_xm_context_t *)mempool);
+ ctx->allocated_memory = mempool; /* Keep original pointer for free() */
+ mempool += sizeof(jar_xm_context_t);
+
+ ctx->rate = rate;
+ mempool = jar_xm_load_module(ctx, moddata, moddata_length, mempool);
+
+ ctx->channels = (jar_xm_channel_context_t*)mempool;
+ mempool += ctx->module.num_channels * sizeof(jar_xm_channel_context_t);
+
+ ctx->global_volume = 1.f;
+ ctx->amplification = .25f; /* XXX: some bad modules may still clip. Find out something better. */
+
+#if JAR_XM_RAMPING
+ ctx->volume_ramp = (1.f / 128.f);
+ ctx->panning_ramp = (1.f / 128.f);
+#endif
+
+ for(uint8_t i = 0; i < ctx->module.num_channels; ++i) {
+ jar_xm_channel_context_t* ch = ctx->channels + i;
+
+ ch->ping = true;
+ ch->vibrato_waveform = jar_xm_SINE_WAVEFORM;
+ ch->vibrato_waveform_retrigger = true;
+ ch->tremolo_waveform = jar_xm_SINE_WAVEFORM;
+ ch->tremolo_waveform_retrigger = true;
+
+ ch->volume = ch->volume_envelope_volume = ch->fadeout_volume = 1.0f;
+ ch->panning = ch->panning_envelope_panning = .5f;
+ ch->actual_volume = .0f;
+ ch->actual_panning = .5f;
+ }
+
+ ctx->row_loop_count = (uint8_t*)mempool;
+ mempool += MAX_NUM_ROWS * sizeof(uint8_t);
+
+#if JAR_XM_DEFENSIVE
+ if((ret = jar_xm_check_sanity_postload(ctx))) {
+ DEBUG("jar_xm_check_sanity_postload() returned %i, module is not safe to play", ret);
+ jar_xm_free_context(ctx);
+ return 1;
+ }
+#endif
+
+ return 0;
+}
+
+void jar_xm_free_context(jar_xm_context_t* ctx) {
+ free(ctx->allocated_memory);
+}
+
+void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt) {
+ ctx->max_loop_count = loopcnt;
+}
+
+uint8_t jar_xm_get_loop_count(jar_xm_context_t* ctx) {
+ return ctx->loop_count;
+}
+
+bool jar_xm_mute_channel(jar_xm_context_t* ctx, uint16_t channel, bool mute) {
+ bool old = ctx->channels[channel - 1].muted;
+ ctx->channels[channel - 1].muted = mute;
+ return old;
+}
+
+bool jar_xm_mute_instrument(jar_xm_context_t* ctx, uint16_t instr, bool mute) {
+ bool old = ctx->module.instruments[instr - 1].muted;
+ ctx->module.instruments[instr - 1].muted = mute;
+ return old;
+}
+
+
+
+const char* jar_xm_get_module_name(jar_xm_context_t* ctx) {
+ return ctx->module.name;
+}
+
+const char* jar_xm_get_tracker_name(jar_xm_context_t* ctx) {
+ return ctx->module.trackername;
+}
+
+
+
+uint16_t jar_xm_get_number_of_channels(jar_xm_context_t* ctx) {
+ return ctx->module.num_channels;
+}
+
+uint16_t jar_xm_get_module_length(jar_xm_context_t* ctx) {
+ return ctx->module.length;
+}
+
+uint16_t jar_xm_get_number_of_patterns(jar_xm_context_t* ctx) {
+ return ctx->module.num_patterns;
+}
+
+uint16_t jar_xm_get_number_of_rows(jar_xm_context_t* ctx, uint16_t pattern) {
+ return ctx->module.patterns[pattern].num_rows;
+}
+
+uint16_t jar_xm_get_number_of_instruments(jar_xm_context_t* ctx) {
+ return ctx->module.num_instruments;
+}
+
+uint16_t jar_xm_get_number_of_samples(jar_xm_context_t* ctx, uint16_t instrument) {
+ return ctx->module.instruments[instrument - 1].num_samples;
+}
+
+
+
+void jar_xm_get_playing_speed(jar_xm_context_t* ctx, uint16_t* bpm, uint16_t* tempo) {
+ if(bpm) *bpm = ctx->bpm;
+ if(tempo) *tempo = ctx->tempo;
+}
+
+void jar_xm_get_position(jar_xm_context_t* ctx, uint8_t* pattern_index, uint8_t* pattern, uint8_t* row, uint64_t* samples) {
+ if(pattern_index) *pattern_index = ctx->current_table_index;
+ if(pattern) *pattern = ctx->module.pattern_table[ctx->current_table_index];
+ if(row) *row = ctx->current_row;
+ if(samples) *samples = ctx->generated_samples;
+}
+
+uint64_t jar_xm_get_latest_trigger_of_instrument(jar_xm_context_t* ctx, uint16_t instr) {
+ return ctx->module.instruments[instr - 1].latest_trigger;
+}
+
+uint64_t jar_xm_get_latest_trigger_of_sample(jar_xm_context_t* ctx, uint16_t instr, uint16_t sample) {
+ return ctx->module.instruments[instr - 1].samples[sample].latest_trigger;
+}
+
+uint64_t jar_xm_get_latest_trigger_of_channel(jar_xm_context_t* ctx, uint16_t chn) {
+ return ctx->channels[chn - 1].latest_trigger;
+}
+
+/* .xm files are little-endian. (XXX: Are they really?) */
+
+/* Bounded reader macros.
+ * If we attempt to read the buffer out-of-bounds, pretend that the buffer is
+ * infinitely padded with zeroes.
+ */
+#define READ_U8(offset) (((offset) < moddata_length) ? (*(uint8_t*)(moddata + (offset))) : 0)
+#define READ_U16(offset) ((uint16_t)READ_U8(offset) | ((uint16_t)READ_U8((offset) + 1) << 8))
+#define READ_U32(offset) ((uint32_t)READ_U16(offset) | ((uint32_t)READ_U16((offset) + 2) << 16))
+#define READ_MEMCPY(ptr, offset, length) memcpy_pad(ptr, length, moddata, moddata_length, offset)
+
+static inline void memcpy_pad(void* dst, size_t dst_len, const void* src, size_t src_len, size_t offset) {
+ uint8_t* dst_c = dst;
+ const uint8_t* src_c = src;
+
+ /* how many bytes can be copied without overrunning `src` */
+ size_t copy_bytes = (src_len >= offset) ? (src_len - offset) : 0;
+ copy_bytes = copy_bytes > dst_len ? dst_len : copy_bytes;
+
+ memcpy(dst_c, src_c + offset, copy_bytes);
+ /* padded bytes */
+ memset(dst_c + copy_bytes, 0, dst_len - copy_bytes);
+}
+
+#if JAR_XM_DEFENSIVE
+
+int jar_xm_check_sanity_preload(const char* module, size_t module_length) {
+ if(module_length < 60) {
+ return 4;
+ }
+
+ if(memcmp("Extended Module: ", module, 17) != 0) {
+ return 1;
+ }
+
+ if(module[37] != 0x1A) {
+ return 2;
+ }
+
+ if(module[59] != 0x01 || module[58] != 0x04) {
+ /* Not XM 1.04 */
+ return 3;
+ }
+
+ return 0;
+}
+
+int jar_xm_check_sanity_postload(jar_xm_context_t* ctx) {
+ /* @todo: plenty of stuff to do here… */
+
+ /* Check the POT */
+ for(uint8_t i = 0; i < ctx->module.length; ++i) {
+ if(ctx->module.pattern_table[i] >= ctx->module.num_patterns) {
+ if(i+1 == ctx->module.length && ctx->module.length > 1) {
+ /* Cheap fix */
+ --ctx->module.length;
+ DEBUG("trimming invalid POT at pos %X", i);
+ } else {
+ DEBUG("module has invalid POT, pos %X references nonexistent pattern %X",
+ i,
+ ctx->module.pattern_table[i]);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif
+
+size_t jar_xm_get_memory_needed_for_context(const char* moddata, size_t moddata_length) {
+ size_t memory_needed = 0;
+ size_t offset = 60; /* Skip the first header */
+ uint16_t num_channels;
+ uint16_t num_patterns;
+ uint16_t num_instruments;
+
+ /* Read the module header */
+
+ num_channels = READ_U16(offset + 8);
+ num_channels = READ_U16(offset + 8);
+
+ num_patterns = READ_U16(offset + 10);
+ memory_needed += num_patterns * sizeof(jar_xm_pattern_t);
+
+ num_instruments = READ_U16(offset + 12);
+ memory_needed += num_instruments * sizeof(jar_xm_instrument_t);
+
+ memory_needed += MAX_NUM_ROWS * READ_U16(offset + 4) * sizeof(uint8_t); /* Module length */
+
+ /* Header size */
+ offset += READ_U32(offset);
+
+ /* Read pattern headers */
+ for(uint16_t i = 0; i < num_patterns; ++i) {
+ uint16_t num_rows;
+
+ num_rows = READ_U16(offset + 5);
+ memory_needed += num_rows * num_channels * sizeof(jar_xm_pattern_slot_t);
+
+ /* Pattern header length + packed pattern data size */
+ offset += READ_U32(offset) + READ_U16(offset + 7);
+ }
+
+ /* Read instrument headers */
+ for(uint16_t i = 0; i < num_instruments; ++i) {
+ uint16_t num_samples;
+ uint32_t sample_header_size = 0;
+ uint32_t sample_size_aggregate = 0;
+
+ num_samples = READ_U16(offset + 27);
+ memory_needed += num_samples * sizeof(jar_xm_sample_t);
+
+ if(num_samples > 0) {
+ sample_header_size = READ_U32(offset + 29);
+ }
+
+ /* Instrument header size */
+ offset += READ_U32(offset);
+
+ for(uint16_t j = 0; j < num_samples; ++j) {
+ uint32_t sample_size;
+ uint8_t flags;
+
+ sample_size = READ_U32(offset);
+ flags = READ_U8(offset + 14);
+ sample_size_aggregate += sample_size;
+
+ if(flags & (1 << 4)) {
+ /* 16 bit sample */
+ memory_needed += sample_size * (sizeof(float) >> 1);
+ } else {
+ /* 8 bit sample */
+ memory_needed += sample_size * sizeof(float);
+ }
+
+ offset += sample_header_size;
+ }
+
+ offset += sample_size_aggregate;
+ }
+
+ memory_needed += num_channels * sizeof(jar_xm_channel_context_t);
+ memory_needed += sizeof(jar_xm_context_t);
+
+ return memory_needed;
+}
+
+char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t moddata_length, char* mempool) {
+ size_t offset = 0;
+ jar_xm_module_t* mod = &(ctx->module);
+
+ /* Read XM header */
+ READ_MEMCPY(mod->name, offset + 17, MODULE_NAME_LENGTH);
+ READ_MEMCPY(mod->trackername, offset + 38, TRACKER_NAME_LENGTH);
+ offset += 60;
+
+ /* Read module header */
+ uint32_t header_size = READ_U32(offset);
+
+ mod->length = READ_U16(offset + 4);
+ mod->restart_position = READ_U16(offset + 6);
+ mod->num_channels = READ_U16(offset + 8);
+ mod->num_patterns = READ_U16(offset + 10);
+ mod->num_instruments = READ_U16(offset + 12);
+
+ mod->patterns = (jar_xm_pattern_t*)mempool;
+ mempool += mod->num_patterns * sizeof(jar_xm_pattern_t);
+
+ mod->instruments = (jar_xm_instrument_t*)mempool;
+ mempool += mod->num_instruments * sizeof(jar_xm_instrument_t);
+
+ uint16_t flags = READ_U32(offset + 14);
+ mod->frequency_type = (flags & (1 << 0)) ? jar_xm_LINEAR_FREQUENCIES : jar_xm_AMIGA_FREQUENCIES;
+
+ ctx->tempo = READ_U16(offset + 16);
+ ctx->bpm = READ_U16(offset + 18);
+
+ READ_MEMCPY(mod->pattern_table, offset + 20, PATTERN_ORDER_TABLE_LENGTH);
+ offset += header_size;
+
+ /* Read patterns */
+ for(uint16_t i = 0; i < mod->num_patterns; ++i) {
+ uint16_t packed_patterndata_size = READ_U16(offset + 7);
+ jar_xm_pattern_t* pat = mod->patterns + i;
+
+ pat->num_rows = READ_U16(offset + 5);
+
+ pat->slots = (jar_xm_pattern_slot_t*)mempool;
+ mempool += mod->num_channels * pat->num_rows * sizeof(jar_xm_pattern_slot_t);
+
+ /* Pattern header length */
+ offset += READ_U32(offset);
+
+ if(packed_patterndata_size == 0) {
+ /* No pattern data is present */
+ memset(pat->slots, 0, sizeof(jar_xm_pattern_slot_t) * pat->num_rows * mod->num_channels);
+ } else {
+ /* This isn't your typical for loop */
+ for(uint16_t j = 0, k = 0; j < packed_patterndata_size; ++k) {
+ uint8_t note = READ_U8(offset + j);
+ jar_xm_pattern_slot_t* slot = pat->slots + k;
+
+ if(note & (1 << 7)) {
+ /* MSB is set, this is a compressed packet */
+ ++j;
+
+ if(note & (1 << 0)) {
+ /* Note follows */
+ slot->note = READ_U8(offset + j);
+ ++j;
+ } else {
+ slot->note = 0;
+ }
+
+ if(note & (1 << 1)) {
+ /* Instrument follows */
+ slot->instrument = READ_U8(offset + j);
+ ++j;
+ } else {
+ slot->instrument = 0;
+ }
+
+ if(note & (1 << 2)) {
+ /* Volume column follows */
+ slot->volume_column = READ_U8(offset + j);
+ ++j;
+ } else {
+ slot->volume_column = 0;
+ }
+
+ if(note & (1 << 3)) {
+ /* Effect follows */
+ slot->effect_type = READ_U8(offset + j);
+ ++j;
+ } else {
+ slot->effect_type = 0;
+ }
+
+ if(note & (1 << 4)) {
+ /* Effect parameter follows */
+ slot->effect_param = READ_U8(offset + j);
+ ++j;
+ } else {
+ slot->effect_param = 0;
+ }
+ } else {
+ /* Uncompressed packet */
+ slot->note = note;
+ slot->instrument = READ_U8(offset + j + 1);
+ slot->volume_column = READ_U8(offset + j + 2);
+ slot->effect_type = READ_U8(offset + j + 3);
+ slot->effect_param = READ_U8(offset + j + 4);
+ j += 5;
+ }
+ }
+ }
+
+ offset += packed_patterndata_size;
+ }
+
+ /* Read instruments */
+ for(uint16_t i = 0; i < ctx->module.num_instruments; ++i) {
+ uint32_t sample_header_size = 0;
+ jar_xm_instrument_t* instr = mod->instruments + i;
+
+ READ_MEMCPY(instr->name, offset + 4, INSTRUMENT_NAME_LENGTH);
+ instr->num_samples = READ_U16(offset + 27);
+
+ if(instr->num_samples > 0) {
+ /* Read extra header properties */
+ sample_header_size = READ_U32(offset + 29);
+ READ_MEMCPY(instr->sample_of_notes, offset + 33, NUM_NOTES);
+
+ instr->volume_envelope.num_points = READ_U8(offset + 225);
+ instr->panning_envelope.num_points = READ_U8(offset + 226);
+
+ for(uint8_t j = 0; j < instr->volume_envelope.num_points; ++j) {
+ instr->volume_envelope.points[j].frame = READ_U16(offset + 129 + 4 * j);
+ instr->volume_envelope.points[j].value = READ_U16(offset + 129 + 4 * j + 2);
+ }
+
+ for(uint8_t j = 0; j < instr->panning_envelope.num_points; ++j) {
+ instr->panning_envelope.points[j].frame = READ_U16(offset + 177 + 4 * j);
+ instr->panning_envelope.points[j].value = READ_U16(offset + 177 + 4 * j + 2);
+ }
+
+ instr->volume_envelope.sustain_point = READ_U8(offset + 227);
+ instr->volume_envelope.loop_start_point = READ_U8(offset + 228);
+ instr->volume_envelope.loop_end_point = READ_U8(offset + 229);
+
+ instr->panning_envelope.sustain_point = READ_U8(offset + 230);
+ instr->panning_envelope.loop_start_point = READ_U8(offset + 231);
+ instr->panning_envelope.loop_end_point = READ_U8(offset + 232);
+
+ uint8_t flags = READ_U8(offset + 233);
+ instr->volume_envelope.enabled = flags & (1 << 0);
+ instr->volume_envelope.sustain_enabled = flags & (1 << 1);
+ instr->volume_envelope.loop_enabled = flags & (1 << 2);
+
+ flags = READ_U8(offset + 234);
+ instr->panning_envelope.enabled = flags & (1 << 0);
+ instr->panning_envelope.sustain_enabled = flags & (1 << 1);
+ instr->panning_envelope.loop_enabled = flags & (1 << 2);
+
+ instr->vibrato_type = READ_U8(offset + 235);
+ if(instr->vibrato_type == 2) {
+ instr->vibrato_type = 1;
+ } else if(instr->vibrato_type == 1) {
+ instr->vibrato_type = 2;
+ }
+ instr->vibrato_sweep = READ_U8(offset + 236);
+ instr->vibrato_depth = READ_U8(offset + 237);
+ instr->vibrato_rate = READ_U8(offset + 238);
+ instr->volume_fadeout = READ_U16(offset + 239);
+
+ instr->samples = (jar_xm_sample_t*)mempool;
+ mempool += instr->num_samples * sizeof(jar_xm_sample_t);
+ } else {
+ instr->samples = NULL;
+ }
+
+ /* Instrument header size */
+ offset += READ_U32(offset);
+
+ for(uint16_t j = 0; j < instr->num_samples; ++j) {
+ /* Read sample header */
+ jar_xm_sample_t* sample = instr->samples + j;
+
+ sample->length = READ_U32(offset);
+ sample->loop_start = READ_U32(offset + 4);
+ sample->loop_length = READ_U32(offset + 8);
+ sample->loop_end = sample->loop_start + sample->loop_length;
+ sample->volume = (float)READ_U8(offset + 12) / (float)0x40;
+ sample->finetune = (int8_t)READ_U8(offset + 13);
+
+ uint8_t flags = READ_U8(offset + 14);
+ if((flags & 3) == 0) {
+ sample->loop_type = jar_xm_NO_LOOP;
+ } else if((flags & 3) == 1) {
+ sample->loop_type = jar_xm_FORWARD_LOOP;
+ } else {
+ sample->loop_type = jar_xm_PING_PONG_LOOP;
+ }
+
+ sample->bits = (flags & (1 << 4)) ? 16 : 8;
+
+ sample->panning = (float)READ_U8(offset + 15) / (float)0xFF;
+ sample->relative_note = (int8_t)READ_U8(offset + 16);
+ READ_MEMCPY(sample->name, 18, SAMPLE_NAME_LENGTH);
+ sample->data = (float*)mempool;
+
+ if(sample->bits == 16) {
+ /* 16 bit sample */
+ mempool += sample->length * (sizeof(float) >> 1);
+ sample->loop_start >>= 1;
+ sample->loop_length >>= 1;
+ sample->loop_end >>= 1;
+ sample->length >>= 1;
+ } else {
+ /* 8 bit sample */
+ mempool += sample->length * sizeof(float);
+ }
+
+ offset += sample_header_size;
+ }
+
+ for(uint16_t j = 0; j < instr->num_samples; ++j) {
+ /* Read sample data */
+ jar_xm_sample_t* sample = instr->samples + j;
+ uint32_t length = sample->length;
+
+ if(sample->bits == 16) {
+ int16_t v = 0;
+ for(uint32_t k = 0; k < length; ++k) {
+ v = v + (int16_t)READ_U16(offset + (k << 1));
+ sample->data[k] = (float)v / (float)(1 << 15);
+ }
+ offset += sample->length << 1;
+ } else {
+ int8_t v = 0;
+ for(uint32_t k = 0; k < length; ++k) {
+ v = v + (int8_t)READ_U8(offset + k);
+ sample->data[k] = (float)v / (float)(1 << 7);
+ }
+ offset += sample->length;
+ }
+ }
+ }
+
+ return mempool;
+}
+
+//-------------------------------------------------------------------------------
+//THE FOLLOWING IS FOR PLAYING
+//-------------------------------------------------------------------------------
+
+/* ----- Static functions ----- */
+
+static float jar_xm_waveform(jar_xm_waveform_type_t, uint8_t);
+static void jar_xm_autovibrato(jar_xm_context_t*, jar_xm_channel_context_t*);
+static void jar_xm_vibrato(jar_xm_context_t*, jar_xm_channel_context_t*, uint8_t, uint16_t);
+static void jar_xm_tremolo(jar_xm_context_t*, jar_xm_channel_context_t*, uint8_t, uint16_t);
+static void jar_xm_arpeggio(jar_xm_context_t*, jar_xm_channel_context_t*, uint8_t, uint16_t);
+static void jar_xm_tone_portamento(jar_xm_context_t*, jar_xm_channel_context_t*);
+static void jar_xm_pitch_slide(jar_xm_context_t*, jar_xm_channel_context_t*, float);
+static void jar_xm_panning_slide(jar_xm_channel_context_t*, uint8_t);
+static void jar_xm_volume_slide(jar_xm_channel_context_t*, uint8_t);
+
+static float jar_xm_envelope_lerp(jar_xm_envelope_point_t*, jar_xm_envelope_point_t*, uint16_t);
+static void jar_xm_envelope_tick(jar_xm_channel_context_t*, jar_xm_envelope_t*, uint16_t*, float*);
+static void jar_xm_envelopes(jar_xm_channel_context_t*);
+
+static float jar_xm_linear_period(float);
+static float jar_xm_linear_frequency(float);
+static float jar_xm_amiga_period(float);
+static float jar_xm_amiga_frequency(float);
+static float jar_xm_period(jar_xm_context_t*, float);
+static float jar_xm_frequency(jar_xm_context_t*, float, float);
+static void jar_xm_update_frequency(jar_xm_context_t*, jar_xm_channel_context_t*);
+
+static void jar_xm_handle_note_and_instrument(jar_xm_context_t*, jar_xm_channel_context_t*, jar_xm_pattern_slot_t*);
+static void jar_xm_trigger_note(jar_xm_context_t*, jar_xm_channel_context_t*, unsigned int flags);
+static void jar_xm_cut_note(jar_xm_channel_context_t*);
+static void jar_xm_key_off(jar_xm_channel_context_t*);
+
+static void jar_xm_post_pattern_change(jar_xm_context_t*);
+static void jar_xm_row(jar_xm_context_t*);
+static void jar_xm_tick(jar_xm_context_t*);
+
+static float jar_xm_next_of_sample(jar_xm_channel_context_t*);
+static void jar_xm_sample(jar_xm_context_t*, float*, float*);
+
+/* ----- Other oddities ----- */
+
+#define jar_xm_TRIGGER_KEEP_VOLUME (1 << 0)
+#define jar_xm_TRIGGER_KEEP_PERIOD (1 << 1)
+#define jar_xm_TRIGGER_KEEP_SAMPLE_POSITION (1 << 2)
+
+static const uint16_t amiga_frequencies[] = {
+ 1712, 1616, 1525, 1440, /* C-2, C#2, D-2, D#2 */
+ 1357, 1281, 1209, 1141, /* E-2, F-2, F#2, G-2 */
+ 1077, 1017, 961, 907, /* G#2, A-2, A#2, B-2 */
+ 856, /* C-3 */
+};
+
+static const float multi_retrig_add[] = {
+ 0.f, -1.f, -2.f, -4.f, /* 0, 1, 2, 3 */
+ -8.f, -16.f, 0.f, 0.f, /* 4, 5, 6, 7 */
+ 0.f, 1.f, 2.f, 4.f, /* 8, 9, A, B */
+ 8.f, 16.f, 0.f, 0.f /* C, D, E, F */
+};
+
+static const float multi_retrig_multiply[] = {
+ 1.f, 1.f, 1.f, 1.f, /* 0, 1, 2, 3 */
+ 1.f, 1.f, .6666667f, .5f, /* 4, 5, 6, 7 */
+ 1.f, 1.f, 1.f, 1.f, /* 8, 9, A, B */
+ 1.f, 1.f, 1.5f, 2.f /* C, D, E, F */
+};
+
+#define jar_xm_CLAMP_UP1F(vol, limit) do { \
+ if((vol) > (limit)) (vol) = (limit); \
+ } while(0)
+#define jar_xm_CLAMP_UP(vol) jar_xm_CLAMP_UP1F((vol), 1.f)
+
+#define jar_xm_CLAMP_DOWN1F(vol, limit) do { \
+ if((vol) < (limit)) (vol) = (limit); \
+ } while(0)
+#define jar_xm_CLAMP_DOWN(vol) jar_xm_CLAMP_DOWN1F((vol), .0f)
+
+#define jar_xm_CLAMP2F(vol, up, down) do { \
+ if((vol) > (up)) (vol) = (up); \
+ else if((vol) < (down)) (vol) = (down); \
+ } while(0)
+#define jar_xm_CLAMP(vol) jar_xm_CLAMP2F((vol), 1.f, .0f)
+
+#define jar_xm_SLIDE_TOWARDS(val, goal, incr) do { \
+ if((val) > (goal)) { \
+ (val) -= (incr); \
+ jar_xm_CLAMP_DOWN1F((val), (goal)); \
+ } else if((val) < (goal)) { \
+ (val) += (incr); \
+ jar_xm_CLAMP_UP1F((val), (goal)); \
+ } \
+ } while(0)
+
+#define jar_xm_LERP(u, v, t) ((u) + (t) * ((v) - (u)))
+#define jar_xm_INVERSE_LERP(u, v, lerp) (((lerp) - (u)) / ((v) - (u)))
+
+#define HAS_TONE_PORTAMENTO(s) ((s)->effect_type == 3 \
+ || (s)->effect_type == 5 \
+ || ((s)->volume_column >> 4) == 0xF)
+#define HAS_ARPEGGIO(s) ((s)->effect_type == 0 \
+ && (s)->effect_param != 0)
+#define HAS_VIBRATO(s) ((s)->effect_type == 4 \
+ || (s)->effect_param == 6 \
+ || ((s)->volume_column >> 4) == 0xB)
+#define NOTE_IS_VALID(n) ((n) > 0 && (n) < 97)
+
+/* ----- Function definitions ----- */
+
+static float jar_xm_waveform(jar_xm_waveform_type_t waveform, uint8_t step) {
+ static unsigned int next_rand = 24492;
+ step %= 0x40;
+
+ switch(waveform) {
+
+ case jar_xm_SINE_WAVEFORM:
+ /* Why not use a table? For saving space, and because there's
+ * very very little actual performance gain. */
+ return -sinf(2.f * 3.141592f * (float)step / (float)0x40);
+
+ case jar_xm_RAMP_DOWN_WAVEFORM:
+ /* Ramp down: 1.0f when step = 0; -1.0f when step = 0x40 */
+ return (float)(0x20 - step) / 0x20;
+
+ case jar_xm_SQUARE_WAVEFORM:
+ /* Square with a 50% duty */
+ return (step >= 0x20) ? 1.f : -1.f;
+
+ case jar_xm_RANDOM_WAVEFORM:
+ /* Use the POSIX.1-2001 example, just to be deterministic
+ * across different machines */
+ next_rand = next_rand * 1103515245 + 12345;
+ return (float)((next_rand >> 16) & 0x7FFF) / (float)0x4000 - 1.f;
+
+ case jar_xm_RAMP_UP_WAVEFORM:
+ /* Ramp up: -1.f when step = 0; 1.f when step = 0x40 */
+ return (float)(step - 0x20) / 0x20;
+
+ default:
+ break;
+
+ }
+
+ return .0f;
+}
+
+static void jar_xm_autovibrato(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch) {
+ if(ch->instrument == NULL || ch->instrument->vibrato_depth == 0) return;
+ jar_xm_instrument_t* instr = ch->instrument;
+ float sweep = 1.f;
+
+ if(ch->autovibrato_ticks < instr->vibrato_sweep) {
+ /* No idea if this is correct, but it sounds close enough… */
+ sweep = jar_xm_LERP(0.f, 1.f, (float)ch->autovibrato_ticks / (float)instr->vibrato_sweep);
+ }
+
+ unsigned int step = ((ch->autovibrato_ticks++) * instr->vibrato_rate) >> 2;
+ ch->autovibrato_note_offset = .25f * jar_xm_waveform(instr->vibrato_type, step)
+ * (float)instr->vibrato_depth / (float)0xF * sweep;
+ jar_xm_update_frequency(ctx, ch);
+}
+
+static void jar_xm_vibrato(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, uint8_t param, uint16_t pos) {
+ unsigned int step = pos * (param >> 4);
+ ch->vibrato_note_offset =
+ 2.f
+ * jar_xm_waveform(ch->vibrato_waveform, step)
+ * (float)(param & 0x0F) / (float)0xF;
+ jar_xm_update_frequency(ctx, ch);
+}
+
+static void jar_xm_tremolo(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, uint8_t param, uint16_t pos) {
+ unsigned int step = pos * (param >> 4);
+ /* Not so sure about this, it sounds correct by ear compared with
+ * MilkyTracker, but it could come from other bugs */
+ ch->tremolo_volume = -1.f * jar_xm_waveform(ch->tremolo_waveform, step)
+ * (float)(param & 0x0F) / (float)0xF;
+}
+
+static void jar_xm_arpeggio(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, uint8_t param, uint16_t tick) {
+ switch(tick % 3) {
+ case 0:
+ ch->arp_in_progress = false;
+ ch->arp_note_offset = 0;
+ break;
+ case 2:
+ ch->arp_in_progress = true;
+ ch->arp_note_offset = param >> 4;
+ break;
+ case 1:
+ ch->arp_in_progress = true;
+ ch->arp_note_offset = param & 0x0F;
+ break;
+ }
+
+ jar_xm_update_frequency(ctx, ch);
+}
+
+static void jar_xm_tone_portamento(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch) {
+ /* 3xx called without a note, wait until we get an actual
+ * target note. */
+ if(ch->tone_portamento_target_period == 0.f) return;
+
+ if(ch->period != ch->tone_portamento_target_period) {
+ jar_xm_SLIDE_TOWARDS(ch->period,
+ ch->tone_portamento_target_period,
+ (ctx->module.frequency_type == jar_xm_LINEAR_FREQUENCIES ?
+ 4.f : 1.f) * ch->tone_portamento_param
+ );
+ jar_xm_update_frequency(ctx, ch);
+ }
+}
+
+static void jar_xm_pitch_slide(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, float period_offset) {
+ /* Don't ask about the 4.f coefficient. I found mention of it
+ * nowhere. Found by earâ„¢. */
+ if(ctx->module.frequency_type == jar_xm_LINEAR_FREQUENCIES) {
+ period_offset *= 4.f;
+ }
+
+ ch->period += period_offset;
+ jar_xm_CLAMP_DOWN(ch->period);
+ /* XXX: upper bound of period ? */
+
+ jar_xm_update_frequency(ctx, ch);
+}
+
+static void jar_xm_panning_slide(jar_xm_channel_context_t* ch, uint8_t rawval) {
+ float f;
+
+ if((rawval & 0xF0) && (rawval & 0x0F)) {
+ /* Illegal state */
+ return;
+ }
+
+ if(rawval & 0xF0) {
+ /* Slide right */
+ f = (float)(rawval >> 4) / (float)0xFF;
+ ch->panning += f;
+ jar_xm_CLAMP_UP(ch->panning);
+ } else {
+ /* Slide left */
+ f = (float)(rawval & 0x0F) / (float)0xFF;
+ ch->panning -= f;
+ jar_xm_CLAMP_DOWN(ch->panning);
+ }
+}
+
+static void jar_xm_volume_slide(jar_xm_channel_context_t* ch, uint8_t rawval) {
+ float f;
+
+ if((rawval & 0xF0) && (rawval & 0x0F)) {
+ /* Illegal state */
+ return;
+ }
+
+ if(rawval & 0xF0) {
+ /* Slide up */
+ f = (float)(rawval >> 4) / (float)0x40;
+ ch->volume += f;
+ jar_xm_CLAMP_UP(ch->volume);
+ } else {
+ /* Slide down */
+ f = (float)(rawval & 0x0F) / (float)0x40;
+ ch->volume -= f;
+ jar_xm_CLAMP_DOWN(ch->volume);
+ }
+}
+
+static float jar_xm_envelope_lerp(jar_xm_envelope_point_t* a, jar_xm_envelope_point_t* b, uint16_t pos) {
+ /* Linear interpolation between two envelope points */
+ if(pos <= a->frame) return a->value;
+ else if(pos >= b->frame) return b->value;
+ else {
+ float p = (float)(pos - a->frame) / (float)(b->frame - a->frame);
+ return a->value * (1 - p) + b->value * p;
+ }
+}
+
+static void jar_xm_post_pattern_change(jar_xm_context_t* ctx) {
+ /* Loop if necessary */
+ if(ctx->current_table_index >= ctx->module.length) {
+ ctx->current_table_index = ctx->module.restart_position;
+ }
+}
+
+static float jar_xm_linear_period(float note) {
+ return 7680.f - note * 64.f;
+}
+
+static float jar_xm_linear_frequency(float period) {
+ return 8363.f * powf(2.f, (4608.f - period) / 768.f);
+}
+
+static float jar_xm_amiga_period(float note) {
+ unsigned int intnote = note;
+ uint8_t a = intnote % 12;
+ int8_t octave = note / 12.f - 2;
+ uint16_t p1 = amiga_frequencies[a], p2 = amiga_frequencies[a + 1];
+
+ if(octave > 0) {
+ p1 >>= octave;
+ p2 >>= octave;
+ } else if(octave < 0) {
+ p1 <<= (-octave);
+ p2 <<= (-octave);
+ }
+
+ return jar_xm_LERP(p1, p2, note - intnote);
+}
+
+static float jar_xm_amiga_frequency(float period) {
+ if(period == .0f) return .0f;
+
+ /* This is the PAL value. No reason to choose this one over the
+ * NTSC value. */
+ return 7093789.2f / (period * 2.f);
+}
+
+static float jar_xm_period(jar_xm_context_t* ctx, float note) {
+ switch(ctx->module.frequency_type) {
+ case jar_xm_LINEAR_FREQUENCIES:
+ return jar_xm_linear_period(note);
+ case jar_xm_AMIGA_FREQUENCIES:
+ return jar_xm_amiga_period(note);
+ }
+ return .0f;
+}
+
+static float jar_xm_frequency(jar_xm_context_t* ctx, float period, float note_offset) {
+ uint8_t a;
+ int8_t octave;
+ float note;
+ uint16_t p1, p2;
+
+ switch(ctx->module.frequency_type) {
+
+ case jar_xm_LINEAR_FREQUENCIES:
+ return jar_xm_linear_frequency(period - 64.f * note_offset);
+
+ case jar_xm_AMIGA_FREQUENCIES:
+ if(note_offset == 0) {
+ /* A chance to escape from insanity */
+ return jar_xm_amiga_frequency(period);
+ }
+
+ /* FIXME: this is very crappy at best */
+ a = octave = 0;
+
+ /* Find the octave of the current period */
+ if(period > amiga_frequencies[0]) {
+ --octave;
+ while(period > (amiga_frequencies[0] << (-octave))) --octave;
+ } else if(period < amiga_frequencies[12]) {
+ ++octave;
+ while(period < (amiga_frequencies[12] >> octave)) ++octave;
+ }
+
+ /* Find the smallest note closest to the current period */
+ for(uint8_t i = 0; i < 12; ++i) {
+ p1 = amiga_frequencies[i], p2 = amiga_frequencies[i + 1];
+
+ if(octave > 0) {
+ p1 >>= octave;
+ p2 >>= octave;
+ } else if(octave < 0) {
+ p1 <<= (-octave);
+ p2 <<= (-octave);
+ }
+
+ if(p2 <= period && period <= p1) {
+ a = i;
+ break;
+ }
+ }
+
+ if(JAR_XM_DEBUG && (p1 < period || p2 > period)) {
+ DEBUG("%i <= %f <= %i should hold but doesn't, this is a bug", p2, period, p1);
+ }
+
+ note = 12.f * (octave + 2) + a + jar_xm_INVERSE_LERP(p1, p2, period);
+
+ return jar_xm_amiga_frequency(jar_xm_amiga_period(note + note_offset));
+
+ }
+
+ return .0f;
+}
+
+static void jar_xm_update_frequency(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch) {
+ ch->frequency = jar_xm_frequency(
+ ctx, ch->period,
+ (ch->arp_note_offset > 0 ? ch->arp_note_offset : (
+ ch->vibrato_note_offset + ch->autovibrato_note_offset
+ ))
+ );
+ ch->step = ch->frequency / ctx->rate;
+}
+
+static void jar_xm_handle_note_and_instrument(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch,
+ jar_xm_pattern_slot_t* s) {
+ if(s->instrument > 0) {
+ if(HAS_TONE_PORTAMENTO(ch->current) && ch->instrument != NULL && ch->sample != NULL) {
+ /* Tone portamento in effect, unclear stuff happens */
+ jar_xm_trigger_note(ctx, ch, jar_xm_TRIGGER_KEEP_PERIOD | jar_xm_TRIGGER_KEEP_SAMPLE_POSITION);
+ } else if(s->instrument > ctx->module.num_instruments) {
+ /* Invalid instrument, Cut current note */
+ jar_xm_cut_note(ch);
+ ch->instrument = NULL;
+ ch->sample = NULL;
+ } else {
+ ch->instrument = ctx->module.instruments + (s->instrument - 1);
+ if(s->note == 0 && ch->sample != NULL) {
+ /* Ghost instrument, trigger note */
+ /* Sample position is kept, but envelopes are reset */
+ jar_xm_trigger_note(ctx, ch, jar_xm_TRIGGER_KEEP_SAMPLE_POSITION);
+ }
+ }
+ }
+
+ if(NOTE_IS_VALID(s->note)) {
+ /* Yes, the real note number is s->note -1. Try finding
+ * THAT in any of the specs! :-) */
+
+ jar_xm_instrument_t* instr = ch->instrument;
+
+ if(HAS_TONE_PORTAMENTO(ch->current) && instr != NULL && ch->sample != NULL) {
+ /* Tone portamento in effect */
+ ch->note = s->note + ch->sample->relative_note + ch->sample->finetune / 128.f - 1.f;
+ ch->tone_portamento_target_period = jar_xm_period(ctx, ch->note);
+ } else if(instr == NULL || ch->instrument->num_samples == 0) {
+ /* Bad instrument */
+ jar_xm_cut_note(ch);
+ } else {
+ if(instr->sample_of_notes[s->note - 1] < instr->num_samples) {
+#if JAR_XM_RAMPING
+ for(unsigned int z = 0; z < jar_xm_SAMPLE_RAMPING_POINTS; ++z) {
+ ch->end_of_previous_sample[z] = jar_xm_next_of_sample(ch);
+ }
+ ch->frame_count = 0;
+#endif
+ ch->sample = instr->samples + instr->sample_of_notes[s->note - 1];
+ ch->orig_note = ch->note = s->note + ch->sample->relative_note
+ + ch->sample->finetune / 128.f - 1.f;
+ if(s->instrument > 0) {
+ jar_xm_trigger_note(ctx, ch, 0);
+ } else {
+ /* Ghost note: keep old volume */
+ jar_xm_trigger_note(ctx, ch, jar_xm_TRIGGER_KEEP_VOLUME);
+ }
+ } else {
+ /* Bad sample */
+ jar_xm_cut_note(ch);
+ }
+ }
+ } else if(s->note == 97) {
+ /* Key Off */
+ jar_xm_key_off(ch);
+ }
+
+ switch(s->volume_column >> 4) {
+
+ case 0x5:
+ if(s->volume_column > 0x50) break;
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ /* Set volume */
+ ch->volume = (float)(s->volume_column - 0x10) / (float)0x40;
+ break;
+
+ case 0x8: /* Fine volume slide down */
+ jar_xm_volume_slide(ch, s->volume_column & 0x0F);
+ break;
+
+ case 0x9: /* Fine volume slide up */
+ jar_xm_volume_slide(ch, s->volume_column << 4);
+ break;
+
+ case 0xA: /* Set vibrato speed */
+ ch->vibrato_param = (ch->vibrato_param & 0x0F) | ((s->volume_column & 0x0F) << 4);
+ break;
+
+ case 0xC: /* Set panning */
+ ch->panning = (float)(
+ ((s->volume_column & 0x0F) << 4) | (s->volume_column & 0x0F)
+ ) / (float)0xFF;
+ break;
+
+ case 0xF: /* Tone portamento */
+ if(s->volume_column & 0x0F) {
+ ch->tone_portamento_param = ((s->volume_column & 0x0F) << 4)
+ | (s->volume_column & 0x0F);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ switch(s->effect_type) {
+
+ case 1: /* 1xx: Portamento up */
+ if(s->effect_param > 0) {
+ ch->portamento_up_param = s->effect_param;
+ }
+ break;
+
+ case 2: /* 2xx: Portamento down */
+ if(s->effect_param > 0) {
+ ch->portamento_down_param = s->effect_param;
+ }
+ break;
+
+ case 3: /* 3xx: Tone portamento */
+ if(s->effect_param > 0) {
+ ch->tone_portamento_param = s->effect_param;
+ }
+ break;
+
+ case 4: /* 4xy: Vibrato */
+ if(s->effect_param & 0x0F) {
+ /* Set vibrato depth */
+ ch->vibrato_param = (ch->vibrato_param & 0xF0) | (s->effect_param & 0x0F);
+ }
+ if(s->effect_param >> 4) {
+ /* Set vibrato speed */
+ ch->vibrato_param = (s->effect_param & 0xF0) | (ch->vibrato_param & 0x0F);
+ }
+ break;
+
+ case 5: /* 5xy: Tone portamento + Volume slide */
+ if(s->effect_param > 0) {
+ ch->volume_slide_param = s->effect_param;
+ }
+ break;
+
+ case 6: /* 6xy: Vibrato + Volume slide */
+ if(s->effect_param > 0) {
+ ch->volume_slide_param = s->effect_param;
+ }
+ break;
+
+ case 7: /* 7xy: Tremolo */
+ if(s->effect_param & 0x0F) {
+ /* Set tremolo depth */
+ ch->tremolo_param = (ch->tremolo_param & 0xF0) | (s->effect_param & 0x0F);
+ }
+ if(s->effect_param >> 4) {
+ /* Set tremolo speed */
+ ch->tremolo_param = (s->effect_param & 0xF0) | (ch->tremolo_param & 0x0F);
+ }
+ break;
+
+ case 8: /* 8xx: Set panning */
+ ch->panning = (float)s->effect_param / (float)0xFF;
+ break;
+
+ case 9: /* 9xx: Sample offset */
+ if(ch->sample != NULL && NOTE_IS_VALID(s->note)) {
+ uint32_t final_offset = s->effect_param << (ch->sample->bits == 16 ? 7 : 8);
+ if(final_offset >= ch->sample->length) {
+ /* Pretend the sample dosen't loop and is done playing */
+ ch->sample_position = -1;
+ break;
+ }
+ ch->sample_position = final_offset;
+ }
+ break;
+
+ case 0xA: /* Axy: Volume slide */
+ if(s->effect_param > 0) {
+ ch->volume_slide_param = s->effect_param;
+ }
+ break;
+
+ case 0xB: /* Bxx: Position jump */
+ if(s->effect_param < ctx->module.length) {
+ ctx->position_jump = true;
+ ctx->jump_dest = s->effect_param;
+ }
+ break;
+
+ case 0xC: /* Cxx: Set volume */
+ ch->volume = (float)((s->effect_param > 0x40)
+ ? 0x40 : s->effect_param) / (float)0x40;
+ break;
+
+ case 0xD: /* Dxx: Pattern break */
+ /* Jump after playing this line */
+ ctx->pattern_break = true;
+ ctx->jump_row = (s->effect_param >> 4) * 10 + (s->effect_param & 0x0F);
+ break;
+
+ case 0xE: /* EXy: Extended command */
+ switch(s->effect_param >> 4) {
+
+ case 1: /* E1y: Fine portamento up */
+ if(s->effect_param & 0x0F) {
+ ch->fine_portamento_up_param = s->effect_param & 0x0F;
+ }
+ jar_xm_pitch_slide(ctx, ch, -ch->fine_portamento_up_param);
+ break;
+
+ case 2: /* E2y: Fine portamento down */
+ if(s->effect_param & 0x0F) {
+ ch->fine_portamento_down_param = s->effect_param & 0x0F;
+ }
+ jar_xm_pitch_slide(ctx, ch, ch->fine_portamento_down_param);
+ break;
+
+ case 4: /* E4y: Set vibrato control */
+ ch->vibrato_waveform = s->effect_param & 3;
+ ch->vibrato_waveform_retrigger = !((s->effect_param >> 2) & 1);
+ break;
+
+ case 5: /* E5y: Set finetune */
+ if(NOTE_IS_VALID(ch->current->note) && ch->sample != NULL) {
+ ch->note = ch->current->note + ch->sample->relative_note +
+ (float)(((s->effect_param & 0x0F) - 8) << 4) / 128.f - 1.f;
+ ch->period = jar_xm_period(ctx, ch->note);
+ jar_xm_update_frequency(ctx, ch);
+ }
+ break;
+
+ case 6: /* E6y: Pattern loop */
+ if(s->effect_param & 0x0F) {
+ if((s->effect_param & 0x0F) == ch->pattern_loop_count) {
+ /* Loop is over */
+ ch->pattern_loop_count = 0;
+ break;
+ }
+
+ /* Jump to the beginning of the loop */
+ ch->pattern_loop_count++;
+ ctx->position_jump = true;
+ ctx->jump_row = ch->pattern_loop_origin;
+ ctx->jump_dest = ctx->current_table_index;
+ } else {
+ /* Set loop start point */
+ ch->pattern_loop_origin = ctx->current_row;
+ /* Replicate FT2 E60 bug */
+ ctx->jump_row = ch->pattern_loop_origin;
+ }
+ break;
+
+ case 7: /* E7y: Set tremolo control */
+ ch->tremolo_waveform = s->effect_param & 3;
+ ch->tremolo_waveform_retrigger = !((s->effect_param >> 2) & 1);
+ break;
+
+ case 0xA: /* EAy: Fine volume slide up */
+ if(s->effect_param & 0x0F) {
+ ch->fine_volume_slide_param = s->effect_param & 0x0F;
+ }
+ jar_xm_volume_slide(ch, ch->fine_volume_slide_param << 4);
+ break;
+
+ case 0xB: /* EBy: Fine volume slide down */
+ if(s->effect_param & 0x0F) {
+ ch->fine_volume_slide_param = s->effect_param & 0x0F;
+ }
+ jar_xm_volume_slide(ch, ch->fine_volume_slide_param);
+ break;
+
+ case 0xD: /* EDy: Note delay */
+ /* XXX: figure this out better. EDx triggers
+ * the note even when there no note and no
+ * instrument. But ED0 acts like like a ghost
+ * note, EDx (x ≠ 0) does not. */
+ if(s->note == 0 && s->instrument == 0) {
+ unsigned int flags = jar_xm_TRIGGER_KEEP_VOLUME;
+
+ if(ch->current->effect_param & 0x0F) {
+ ch->note = ch->orig_note;
+ jar_xm_trigger_note(ctx, ch, flags);
+ } else {
+ jar_xm_trigger_note(
+ ctx, ch,
+ flags
+ | jar_xm_TRIGGER_KEEP_PERIOD
+ | jar_xm_TRIGGER_KEEP_SAMPLE_POSITION
+ );
+ }
+ }
+ break;
+
+ case 0xE: /* EEy: Pattern delay */
+ ctx->extra_ticks = (ch->current->effect_param & 0x0F) * ctx->tempo;
+ break;
+
+ default:
+ break;
+
+ }
+ break;
+
+ case 0xF: /* Fxx: Set tempo/BPM */
+ if(s->effect_param > 0) {
+ if(s->effect_param <= 0x1F) {
+ ctx->tempo = s->effect_param;
+ } else {
+ ctx->bpm = s->effect_param;
+ }
+ }
+ break;
+
+ case 16: /* Gxx: Set global volume */
+ ctx->global_volume = (float)((s->effect_param > 0x40)
+ ? 0x40 : s->effect_param) / (float)0x40;
+ break;
+
+ case 17: /* Hxy: Global volume slide */
+ if(s->effect_param > 0) {
+ ch->global_volume_slide_param = s->effect_param;
+ }
+ break;
+
+ case 21: /* Lxx: Set envelope position */
+ ch->volume_envelope_frame_count = s->effect_param;
+ ch->panning_envelope_frame_count = s->effect_param;
+ break;
+
+ case 25: /* Pxy: Panning slide */
+ if(s->effect_param > 0) {
+ ch->panning_slide_param = s->effect_param;
+ }
+ break;
+
+ case 27: /* Rxy: Multi retrig note */
+ if(s->effect_param > 0) {
+ if((s->effect_param >> 4) == 0) {
+ /* Keep previous x value */
+ ch->multi_retrig_param = (ch->multi_retrig_param & 0xF0) | (s->effect_param & 0x0F);
+ } else {
+ ch->multi_retrig_param = s->effect_param;
+ }
+ }
+ break;
+
+ case 29: /* Txy: Tremor */
+ if(s->effect_param > 0) {
+ /* Tremor x and y params do not appear to be separately
+ * kept in memory, unlike Rxy */
+ ch->tremor_param = s->effect_param;
+ }
+ break;
+
+ case 33: /* Xxy: Extra stuff */
+ switch(s->effect_param >> 4) {
+
+ case 1: /* X1y: Extra fine portamento up */
+ if(s->effect_param & 0x0F) {
+ ch->extra_fine_portamento_up_param = s->effect_param & 0x0F;
+ }
+ jar_xm_pitch_slide(ctx, ch, -1.0f * ch->extra_fine_portamento_up_param);
+ break;
+
+ case 2: /* X2y: Extra fine portamento down */
+ if(s->effect_param & 0x0F) {
+ ch->extra_fine_portamento_down_param = s->effect_param & 0x0F;
+ }
+ jar_xm_pitch_slide(ctx, ch, ch->extra_fine_portamento_down_param);
+ break;
+
+ default:
+ break;
+
+ }
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+static void jar_xm_trigger_note(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, unsigned int flags) {
+ if(!(flags & jar_xm_TRIGGER_KEEP_SAMPLE_POSITION)) {
+ ch->sample_position = 0.f;
+ ch->ping = true;
+ }
+
+ if(ch->sample != NULL) {
+ if(!(flags & jar_xm_TRIGGER_KEEP_VOLUME)) {
+ ch->volume = ch->sample->volume;
+ }
+
+ ch->panning = ch->sample->panning;
+ }
+
+ ch->sustained = true;
+ ch->fadeout_volume = ch->volume_envelope_volume = 1.0f;
+ ch->panning_envelope_panning = .5f;
+ ch->volume_envelope_frame_count = ch->panning_envelope_frame_count = 0;
+ ch->vibrato_note_offset = 0.f;
+ ch->tremolo_volume = 0.f;
+ ch->tremor_on = false;
+
+ ch->autovibrato_ticks = 0;
+
+ if(ch->vibrato_waveform_retrigger) {
+ ch->vibrato_ticks = 0; /* XXX: should the waveform itself also
+ * be reset to sine? */
+ }
+ if(ch->tremolo_waveform_retrigger) {
+ ch->tremolo_ticks = 0;
+ }
+
+ if(!(flags & jar_xm_TRIGGER_KEEP_PERIOD)) {
+ ch->period = jar_xm_period(ctx, ch->note);
+ jar_xm_update_frequency(ctx, ch);
+ }
+
+ ch->latest_trigger = ctx->generated_samples;
+ if(ch->instrument != NULL) {
+ ch->instrument->latest_trigger = ctx->generated_samples;
+ }
+ if(ch->sample != NULL) {
+ ch->sample->latest_trigger = ctx->generated_samples;
+ }
+}
+
+static void jar_xm_cut_note(jar_xm_channel_context_t* ch) {
+ /* NB: this is not the same as Key Off */
+ ch->volume = .0f;
+}
+
+static void jar_xm_key_off(jar_xm_channel_context_t* ch) {
+ /* Key Off */
+ ch->sustained = false;
+
+ /* If no volume envelope is used, also cut the note */
+ if(ch->instrument == NULL || !ch->instrument->volume_envelope.enabled) {
+ jar_xm_cut_note(ch);
+ }
+}
+
+static void jar_xm_row(jar_xm_context_t* ctx) {
+ if(ctx->position_jump) {
+ ctx->current_table_index = ctx->jump_dest;
+ ctx->current_row = ctx->jump_row;
+ ctx->position_jump = false;
+ ctx->pattern_break = false;
+ ctx->jump_row = 0;
+ jar_xm_post_pattern_change(ctx);
+ } else if(ctx->pattern_break) {
+ ctx->current_table_index++;
+ ctx->current_row = ctx->jump_row;
+ ctx->pattern_break = false;
+ ctx->jump_row = 0;
+ jar_xm_post_pattern_change(ctx);
+ }
+
+ jar_xm_pattern_t* cur = ctx->module.patterns + ctx->module.pattern_table[ctx->current_table_index];
+ bool in_a_loop = false;
+
+ /* Read notes… */
+ for(uint8_t i = 0; i < ctx->module.num_channels; ++i) {
+ jar_xm_pattern_slot_t* s = cur->slots + ctx->current_row * ctx->module.num_channels + i;
+ jar_xm_channel_context_t* ch = ctx->channels + i;
+
+ ch->current = s;
+
+ if(s->effect_type != 0xE || s->effect_param >> 4 != 0xD) {
+ jar_xm_handle_note_and_instrument(ctx, ch, s);
+ } else {
+ ch->note_delay_param = s->effect_param & 0x0F;
+ }
+
+ if(!in_a_loop && ch->pattern_loop_count > 0) {
+ in_a_loop = true;
+ }
+ }
+
+ if(!in_a_loop) {
+ /* No E6y loop is in effect (or we are in the first pass) */
+ ctx->loop_count = (ctx->row_loop_count[MAX_NUM_ROWS * ctx->current_table_index + ctx->current_row]++);
+ }
+
+ ctx->current_row++; /* Since this is an uint8, this line can
+ * increment from 255 to 0, in which case it
+ * is still necessary to go the next
+ * pattern. */
+ if(!ctx->position_jump && !ctx->pattern_break &&
+ (ctx->current_row >= cur->num_rows || ctx->current_row == 0)) {
+ ctx->current_table_index++;
+ ctx->current_row = ctx->jump_row; /* This will be 0 most of
+ * the time, except when E60
+ * is used */
+ ctx->jump_row = 0;
+ jar_xm_post_pattern_change(ctx);
+ }
+}
+
+static void jar_xm_envelope_tick(jar_xm_channel_context_t* ch,
+ jar_xm_envelope_t* env,
+ uint16_t* counter,
+ float* outval) {
+ if(env->num_points < 2) {
+ /* Don't really know what to do… */
+ if(env->num_points == 1) {
+ /* XXX I am pulling this out of my ass */
+ *outval = (float)env->points[0].value / (float)0x40;
+ if(*outval > 1) {
+ *outval = 1;
+ }
+ }
+
+ return;
+ } else {
+ uint8_t j;
+
+ if(env->loop_enabled) {
+ uint16_t loop_start = env->points[env->loop_start_point].frame;
+ uint16_t loop_end = env->points[env->loop_end_point].frame;
+ uint16_t loop_length = loop_end - loop_start;
+
+ if(*counter >= loop_end) {
+ *counter -= loop_length;
+ }
+ }
+
+ for(j = 0; j < (env->num_points - 2); ++j) {
+ if(env->points[j].frame <= *counter &&
+ env->points[j+1].frame >= *counter) {
+ break;
+ }
+ }
+
+ *outval = jar_xm_envelope_lerp(env->points + j, env->points + j + 1, *counter) / (float)0x40;
+
+ /* Make sure it is safe to increment frame count */
+ if(!ch->sustained || !env->sustain_enabled ||
+ *counter != env->points[env->sustain_point].frame) {
+ (*counter)++;
+ }
+ }
+}
+
+static void jar_xm_envelopes(jar_xm_channel_context_t* ch) {
+ if(ch->instrument != NULL) {
+ if(ch->instrument->volume_envelope.enabled) {
+ if(!ch->sustained) {
+ ch->fadeout_volume -= (float)ch->instrument->volume_fadeout / 65536.f;
+ jar_xm_CLAMP_DOWN(ch->fadeout_volume);
+ }
+
+ jar_xm_envelope_tick(ch,
+ &(ch->instrument->volume_envelope),
+ &(ch->volume_envelope_frame_count),
+ &(ch->volume_envelope_volume));
+ }
+
+ if(ch->instrument->panning_envelope.enabled) {
+ jar_xm_envelope_tick(ch,
+ &(ch->instrument->panning_envelope),
+ &(ch->panning_envelope_frame_count),
+ &(ch->panning_envelope_panning));
+ }
+ }
+}
+
+static void jar_xm_tick(jar_xm_context_t* ctx) {
+ if(ctx->current_tick == 0) {
+ jar_xm_row(ctx);
+ }
+
+ for(uint8_t i = 0; i < ctx->module.num_channels; ++i) {
+ jar_xm_channel_context_t* ch = ctx->channels + i;
+
+ jar_xm_envelopes(ch);
+ jar_xm_autovibrato(ctx, ch);
+
+ if(ch->arp_in_progress && !HAS_ARPEGGIO(ch->current)) {
+ ch->arp_in_progress = false;
+ ch->arp_note_offset = 0;
+ jar_xm_update_frequency(ctx, ch);
+ }
+ if(ch->vibrato_in_progress && !HAS_VIBRATO(ch->current)) {
+ ch->vibrato_in_progress = false;
+ ch->vibrato_note_offset = 0.f;
+ jar_xm_update_frequency(ctx, ch);
+ }
+
+ switch(ch->current->volume_column >> 4) {
+
+ case 0x6: /* Volume slide down */
+ if(ctx->current_tick == 0) break;
+ jar_xm_volume_slide(ch, ch->current->volume_column & 0x0F);
+ break;
+
+ case 0x7: /* Volume slide up */
+ if(ctx->current_tick == 0) break;
+ jar_xm_volume_slide(ch, ch->current->volume_column << 4);
+ break;
+
+ case 0xB: /* Vibrato */
+ if(ctx->current_tick == 0) break;
+ ch->vibrato_in_progress = false;
+ jar_xm_vibrato(ctx, ch, ch->vibrato_param, ch->vibrato_ticks++);
+ break;
+
+ case 0xD: /* Panning slide left */
+ if(ctx->current_tick == 0) break;
+ jar_xm_panning_slide(ch, ch->current->volume_column & 0x0F);
+ break;
+
+ case 0xE: /* Panning slide right */
+ if(ctx->current_tick == 0) break;
+ jar_xm_panning_slide(ch, ch->current->volume_column << 4);
+ break;
+
+ case 0xF: /* Tone portamento */
+ if(ctx->current_tick == 0) break;
+ jar_xm_tone_portamento(ctx, ch);
+ break;
+
+ default:
+ break;
+
+ }
+
+ switch(ch->current->effect_type) {
+
+ case 0: /* 0xy: Arpeggio */
+ if(ch->current->effect_param > 0) {
+ char arp_offset = ctx->tempo % 3;
+ switch(arp_offset) {
+ case 2: /* 0 -> x -> 0 -> y -> x -> … */
+ if(ctx->current_tick == 1) {
+ ch->arp_in_progress = true;
+ ch->arp_note_offset = ch->current->effect_param >> 4;
+ jar_xm_update_frequency(ctx, ch);
+ break;
+ }
+ /* No break here, this is intended */
+ case 1: /* 0 -> 0 -> y -> x -> … */
+ if(ctx->current_tick == 0) {
+ ch->arp_in_progress = false;
+ ch->arp_note_offset = 0;
+ jar_xm_update_frequency(ctx, ch);
+ break;
+ }
+ /* No break here, this is intended */
+ case 0: /* 0 -> y -> x -> … */
+ jar_xm_arpeggio(ctx, ch, ch->current->effect_param, ctx->current_tick - arp_offset);
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 1: /* 1xx: Portamento up */
+ if(ctx->current_tick == 0) break;
+ jar_xm_pitch_slide(ctx, ch, -ch->portamento_up_param);
+ break;
+
+ case 2: /* 2xx: Portamento down */
+ if(ctx->current_tick == 0) break;
+ jar_xm_pitch_slide(ctx, ch, ch->portamento_down_param);
+ break;
+
+ case 3: /* 3xx: Tone portamento */
+ if(ctx->current_tick == 0) break;
+ jar_xm_tone_portamento(ctx, ch);
+ break;
+
+ case 4: /* 4xy: Vibrato */
+ if(ctx->current_tick == 0) break;
+ ch->vibrato_in_progress = true;
+ jar_xm_vibrato(ctx, ch, ch->vibrato_param, ch->vibrato_ticks++);
+ break;
+
+ case 5: /* 5xy: Tone portamento + Volume slide */
+ if(ctx->current_tick == 0) break;
+ jar_xm_tone_portamento(ctx, ch);
+ jar_xm_volume_slide(ch, ch->volume_slide_param);
+ break;
+
+ case 6: /* 6xy: Vibrato + Volume slide */
+ if(ctx->current_tick == 0) break;
+ ch->vibrato_in_progress = true;
+ jar_xm_vibrato(ctx, ch, ch->vibrato_param, ch->vibrato_ticks++);
+ jar_xm_volume_slide(ch, ch->volume_slide_param);
+ break;
+
+ case 7: /* 7xy: Tremolo */
+ if(ctx->current_tick == 0) break;
+ jar_xm_tremolo(ctx, ch, ch->tremolo_param, ch->tremolo_ticks++);
+ break;
+
+ case 0xA: /* Axy: Volume slide */
+ if(ctx->current_tick == 0) break;
+ jar_xm_volume_slide(ch, ch->volume_slide_param);
+ break;
+
+ case 0xE: /* EXy: Extended command */
+ switch(ch->current->effect_param >> 4) {
+
+ case 0x9: /* E9y: Retrigger note */
+ if(ctx->current_tick != 0 && ch->current->effect_param & 0x0F) {
+ if(!(ctx->current_tick % (ch->current->effect_param & 0x0F))) {
+ jar_xm_trigger_note(ctx, ch, 0);
+ jar_xm_envelopes(ch);
+ }
+ }
+ break;
+
+ case 0xC: /* ECy: Note cut */
+ if((ch->current->effect_param & 0x0F) == ctx->current_tick) {
+ jar_xm_cut_note(ch);
+ }
+ break;
+
+ case 0xD: /* EDy: Note delay */
+ if(ch->note_delay_param == ctx->current_tick) {
+ jar_xm_handle_note_and_instrument(ctx, ch, ch->current);
+ jar_xm_envelopes(ch);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ break;
+
+ case 17: /* Hxy: Global volume slide */
+ if(ctx->current_tick == 0) break;
+ if((ch->global_volume_slide_param & 0xF0) &&
+ (ch->global_volume_slide_param & 0x0F)) {
+ /* Illegal state */
+ break;
+ }
+ if(ch->global_volume_slide_param & 0xF0) {
+ /* Global slide up */
+ float f = (float)(ch->global_volume_slide_param >> 4) / (float)0x40;
+ ctx->global_volume += f;
+ jar_xm_CLAMP_UP(ctx->global_volume);
+ } else {
+ /* Global slide down */
+ float f = (float)(ch->global_volume_slide_param & 0x0F) / (float)0x40;
+ ctx->global_volume -= f;
+ jar_xm_CLAMP_DOWN(ctx->global_volume);
+ }
+ break;
+
+ case 20: /* Kxx: Key off */
+ /* Most documentations will tell you the parameter has no
+ * use. Don't be fooled. */
+ if(ctx->current_tick == ch->current->effect_param) {
+ jar_xm_key_off(ch);
+ }
+ break;
+
+ case 25: /* Pxy: Panning slide */
+ if(ctx->current_tick == 0) break;
+ jar_xm_panning_slide(ch, ch->panning_slide_param);
+ break;
+
+ case 27: /* Rxy: Multi retrig note */
+ if(ctx->current_tick == 0) break;
+ if(((ch->multi_retrig_param) & 0x0F) == 0) break;
+ if((ctx->current_tick % (ch->multi_retrig_param & 0x0F)) == 0) {
+ float v = ch->volume * multi_retrig_multiply[ch->multi_retrig_param >> 4]
+ + multi_retrig_add[ch->multi_retrig_param >> 4];
+ jar_xm_CLAMP(v);
+ jar_xm_trigger_note(ctx, ch, 0);
+ ch->volume = v;
+ }
+ break;
+
+ case 29: /* Txy: Tremor */
+ if(ctx->current_tick == 0) break;
+ ch->tremor_on = (
+ (ctx->current_tick - 1) % ((ch->tremor_param >> 4) + (ch->tremor_param & 0x0F) + 2)
+ >
+ (ch->tremor_param >> 4)
+ );
+ break;
+
+ default:
+ break;
+
+ }
+
+ float panning, volume;
+
+ panning = ch->panning +
+ (ch->panning_envelope_panning - .5f) * (.5f - fabsf(ch->panning - .5f)) * 2.0f;
+
+ if(ch->tremor_on) {
+ volume = .0f;
+ } else {
+ volume = ch->volume + ch->tremolo_volume;
+ jar_xm_CLAMP(volume);
+ volume *= ch->fadeout_volume * ch->volume_envelope_volume;
+ }
+
+#if JAR_XM_RAMPING
+ ch->target_panning = panning;
+ ch->target_volume = volume;
+#else
+ ch->actual_panning = panning;
+ ch->actual_volume = volume;
+#endif
+ }
+
+ ctx->current_tick++;
+ if(ctx->current_tick >= ctx->tempo + ctx->extra_ticks) {
+ ctx->current_tick = 0;
+ ctx->extra_ticks = 0;
+ }
+
+ /* FT2 manual says number of ticks / second = BPM * 0.4 */
+ ctx->remaining_samples_in_tick += (float)ctx->rate / ((float)ctx->bpm * 0.4f);
+}
+
+static float jar_xm_next_of_sample(jar_xm_channel_context_t* ch) {
+ if(ch->instrument == NULL || ch->sample == NULL || ch->sample_position < 0) {
+#if JAR_XM_RAMPING
+ if(ch->frame_count < jar_xm_SAMPLE_RAMPING_POINTS) {
+ return jar_xm_LERP(ch->end_of_previous_sample[ch->frame_count], .0f,
+ (float)ch->frame_count / (float)jar_xm_SAMPLE_RAMPING_POINTS);
+ }
+#endif
+ return .0f;
+ }
+ if(ch->sample->length == 0) {
+ return .0f;
+ }
+
+ float u, v, t;
+ uint32_t a, b;
+ a = (uint32_t)ch->sample_position; /* This cast is fine,
+ * sample_position will not
+ * go above integer
+ * ranges */
+ if(JAR_XM_LINEAR_INTERPOLATION) {
+ b = a + 1;
+ t = ch->sample_position - a; /* Cheaper than fmodf(., 1.f) */
+ }
+ u = ch->sample->data[a];
+
+ switch(ch->sample->loop_type) {
+
+ case jar_xm_NO_LOOP:
+ if(JAR_XM_LINEAR_INTERPOLATION) {
+ v = (b < ch->sample->length) ? ch->sample->data[b] : .0f;
+ }
+ ch->sample_position += ch->step;
+ if(ch->sample_position >= ch->sample->length) {
+ ch->sample_position = -1;
+ }
+ break;
+
+ case jar_xm_FORWARD_LOOP:
+ if(JAR_XM_LINEAR_INTERPOLATION) {
+ v = ch->sample->data[
+ (b == ch->sample->loop_end) ? ch->sample->loop_start : b
+ ];
+ }
+ ch->sample_position += ch->step;
+ while(ch->sample_position >= ch->sample->loop_end) {
+ ch->sample_position -= ch->sample->loop_length;
+ }
+ break;
+
+ case jar_xm_PING_PONG_LOOP:
+ if(ch->ping) {
+ ch->sample_position += ch->step;
+ } else {
+ ch->sample_position -= ch->step;
+ }
+ /* XXX: this may not work for very tight ping-pong loops
+ * (ie switches direction more than once per sample */
+ if(ch->ping) {
+ if(JAR_XM_LINEAR_INTERPOLATION) {
+ v = (b >= ch->sample->loop_end) ? ch->sample->data[a] : ch->sample->data[b];
+ }
+ if(ch->sample_position >= ch->sample->loop_end) {
+ ch->ping = false;
+ ch->sample_position = (ch->sample->loop_end << 1) - ch->sample_position;
+ }
+ /* sanity checking */
+ if(ch->sample_position >= ch->sample->length) {
+ ch->ping = false;
+ ch->sample_position -= ch->sample->length - 1;
+ }
+ } else {
+ if(JAR_XM_LINEAR_INTERPOLATION) {
+ v = u;
+ u = (b == 1 || b - 2 <= ch->sample->loop_start) ? ch->sample->data[a] : ch->sample->data[b - 2];
+ }
+ if(ch->sample_position <= ch->sample->loop_start) {
+ ch->ping = true;
+ ch->sample_position = (ch->sample->loop_start << 1) - ch->sample_position;
+ }
+ /* sanity checking */
+ if(ch->sample_position <= .0f) {
+ ch->ping = true;
+ ch->sample_position = .0f;
+ }
+ }
+ break;
+
+ default:
+ v = .0f;
+ break;
+ }
+
+ float endval = JAR_XM_LINEAR_INTERPOLATION ? jar_xm_LERP(u, v, t) : u;
+
+#if JAR_XM_RAMPING
+ if(ch->frame_count < jar_xm_SAMPLE_RAMPING_POINTS) {
+ /* Smoothly transition between old and new sample. */
+ return jar_xm_LERP(ch->end_of_previous_sample[ch->frame_count], endval,
+ (float)ch->frame_count / (float)jar_xm_SAMPLE_RAMPING_POINTS);
+ }
+#endif
+
+ return endval;
+}
+
+static void jar_xm_sample(jar_xm_context_t* ctx, float* left, float* right) {
+ if(ctx->remaining_samples_in_tick <= 0) {
+ jar_xm_tick(ctx);
+ }
+ ctx->remaining_samples_in_tick--;
+
+ *left = 0.f;
+ *right = 0.f;
+
+ if(ctx->max_loop_count > 0 && ctx->loop_count >= ctx->max_loop_count) {
+ return;
+ }
+
+ for(uint8_t i = 0; i < ctx->module.num_channels; ++i) {
+ jar_xm_channel_context_t* ch = ctx->channels + i;
+
+ if(ch->instrument == NULL || ch->sample == NULL || ch->sample_position < 0) {
+ continue;
+ }
+
+ const float fval = jar_xm_next_of_sample(ch);
+
+ if(!ch->muted && !ch->instrument->muted) {
+ *left += fval * ch->actual_volume * (1.f - ch->actual_panning);
+ *right += fval * ch->actual_volume * ch->actual_panning;
+ }
+
+#if JAR_XM_RAMPING
+ ch->frame_count++;
+ jar_xm_SLIDE_TOWARDS(ch->actual_volume, ch->target_volume, ctx->volume_ramp);
+ jar_xm_SLIDE_TOWARDS(ch->actual_panning, ch->target_panning, ctx->panning_ramp);
+#endif
+ }
+
+ const float fgvol = ctx->global_volume * ctx->amplification;
+ *left *= fgvol;
+ *right *= fgvol;
+
+#if JAR_XM_DEBUG
+ if(fabs(*left) > 1 || fabs(*right) > 1) {
+ DEBUG("clipping frame: %f %f, this is a bad module or a libxm bug", *left, *right);
+ }
+#endif
+}
+
+void jar_xm_generate_samples(jar_xm_context_t* ctx, float* output, size_t numsamples) {
+ if(ctx && output) {
+ ctx->generated_samples += numsamples;
+ for(size_t i = 0; i < numsamples; i++) {
+ jar_xm_sample(ctx, output + (2 * i), output + (2 * i + 1));
+ }
+ }
+}
+
+uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx)
+{
+ uint64_t total = 0;
+ uint8_t currentLoopCount = jar_xm_get_loop_count(ctx);
+ jar_xm_set_max_loop_count(ctx, 0);
+
+ while(jar_xm_get_loop_count(ctx) == currentLoopCount)
+ {
+ total += ctx->remaining_samples_in_tick;
+ ctx->remaining_samples_in_tick = 0;
+ jar_xm_tick(ctx);
+ }
+
+ ctx->loop_count = currentLoopCount;
+ return total;
+}
+
+
+
+
+
+//--------------------------------------------
+//FILE LOADER - TODO - NEEDS TO BE CLEANED UP
+//--------------------------------------------
+
+
+
+#undef DEBUG
+#define DEBUG(...) do { \
+ fprintf(stderr, __VA_ARGS__); \
+ fflush(stderr); \
+ } while(0)
+
+#define DEBUG_ERR(...) do { \
+ fprintf(stderr, __VA_ARGS__); \
+ fflush(stderr); \
+ } while(0)
+
+#define FATAL(...) do { \
+ fprintf(stderr, __VA_ARGS__); \
+ fflush(stderr); \
+ exit(1); \
+ } while(0)
+
+#define FATAL_ERR(...) do { \
+ fprintf(stderr, __VA_ARGS__); \
+ fflush(stderr); \
+ exit(1); \
+ } while(0)
+
+
+int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const char* filename) {
+ FILE* xmf;
+ int size;
+
+ xmf = fopen(filename, "rb");
+ if(xmf == NULL) {
+ DEBUG_ERR("Could not open input file");
+ *ctx = NULL;
+ return 3;
+ }
+
+ fseek(xmf, 0, SEEK_END);
+ size = ftell(xmf);
+ rewind(xmf);
+ if(size == -1) {
+ fclose(xmf);
+ DEBUG_ERR("fseek() failed");
+ *ctx = NULL;
+ return 4;
+ }
+
+ char* data = malloc(size + 1);
+ if(fread(data, 1, size, xmf) < size) {
+ fclose(xmf);
+ DEBUG_ERR("fread() failed");
+ *ctx = NULL;
+ return 5;
+ }
+
+ fclose(xmf);
+
+ switch(jar_xm_create_context_safe(ctx, data, size, rate)) {
+ case 0:
+ break;
+
+ case 1:
+ DEBUG("could not create context: module is not sane\n");
+ *ctx = NULL;
+ return 1;
+ break;
+
+ case 2:
+ FATAL("could not create context: malloc failed\n");
+ return 2;
+ break;
+
+ default:
+ FATAL("could not create context: unknown error\n");
+ return 6;
+ break;
+
+ }
+
+ return 0;
+}
+
+
+
+
+#endif//end of JAR_XM_IMPLEMENTATION
+//-------------------------------------------------------------------------------
+
+
+
+
+#endif//end of INCLUDE_JAR_XM_H
diff --git a/src/external/lua/include/lauxlib.h b/src/external/lua/include/lauxlib.h
new file mode 100644
index 00000000..ddb7c228
--- /dev/null
+++ b/src/external/lua/include/lauxlib.h
@@ -0,0 +1,256 @@
+/*
+** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lauxlib_h
+#define lauxlib_h
+
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "lua.h"
+
+
+
+/* extra error code for 'luaL_load' */
+#define LUA_ERRFILE (LUA_ERRERR+1)
+
+
+typedef struct luaL_Reg {
+ const char *name;
+ lua_CFunction func;
+} luaL_Reg;
+
+
+#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number))
+
+LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz);
+#define luaL_checkversion(L) \
+ luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES)
+
+LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
+LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
+LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
+LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
+LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
+ size_t *l);
+LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
+ const char *def, size_t *l);
+LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);
+LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);
+
+LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);
+LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,
+ lua_Integer def);
+
+LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
+LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
+LUALIB_API void (luaL_checkany) (lua_State *L, int arg);
+
+LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
+LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
+LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
+LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
+
+LUALIB_API void (luaL_where) (lua_State *L, int lvl);
+LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
+
+LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
+ const char *const lst[]);
+
+LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
+LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
+
+/* predefined references */
+#define LUA_NOREF (-2)
+#define LUA_REFNIL (-1)
+
+LUALIB_API int (luaL_ref) (lua_State *L, int t);
+LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
+
+LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
+ const char *mode);
+
+#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
+
+LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
+ const char *name, const char *mode);
+LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
+
+LUALIB_API lua_State *(luaL_newstate) (void);
+
+LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
+
+LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
+ const char *r);
+
+LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
+
+LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
+
+LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
+ const char *msg, int level);
+
+LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
+ lua_CFunction openf, int glb);
+
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+
+#define luaL_newlibtable(L,l) \
+ lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
+
+#define luaL_newlib(L,l) \
+ (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
+
+#define luaL_argcheck(L, cond,arg,extramsg) \
+ ((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
+#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
+#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
+
+#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
+
+#define luaL_dofile(L, fn) \
+ (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_dostring(L, s) \
+ (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
+
+#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
+
+#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+typedef struct luaL_Buffer {
+ char *b; /* buffer address */
+ size_t size; /* buffer size */
+ size_t n; /* number of characters in buffer */
+ lua_State *L;
+ char initb[LUAL_BUFFERSIZE]; /* initial buffer */
+} luaL_Buffer;
+
+
+#define luaL_addchar(B,c) \
+ ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
+ ((B)->b[(B)->n++] = (c)))
+
+#define luaL_addsize(B,s) ((B)->n += (s))
+
+LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
+LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
+LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
+LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
+LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
+LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
+LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
+LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
+
+#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** File handles for IO library
+** =======================================================
+*/
+
+/*
+** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
+** initial structure 'luaL_Stream' (it may contain other fields
+** after that initial structure).
+*/
+
+#define LUA_FILEHANDLE "FILE*"
+
+
+typedef struct luaL_Stream {
+ FILE *f; /* stream (NULL for incompletely created streams) */
+ lua_CFunction closef; /* to close stream (NULL for closed streams) */
+} luaL_Stream;
+
+/* }====================================================== */
+
+
+
+/* compatibility with old module system */
+#if defined(LUA_COMPAT_MODULE)
+
+LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
+ int sizehint);
+LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
+ const luaL_Reg *l, int nup);
+
+#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))
+
+#endif
+
+
+/*
+** {==================================================================
+** "Abstraction Layer" for basic report of messages and errors
+** ===================================================================
+*/
+
+/* print a string */
+#if !defined(lua_writestring)
+#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
+#endif
+
+/* print a newline and flush the output */
+#if !defined(lua_writeline)
+#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
+#endif
+
+/* print an error message */
+#if !defined(lua_writestringerror)
+#define lua_writestringerror(s,p) \
+ (fprintf(stderr, (s), (p)), fflush(stderr))
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {============================================================
+** Compatibility with deprecated conversions
+** =============================================================
+*/
+#if defined(LUA_COMPAT_APIINTCASTS)
+
+#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a))
+#define luaL_optunsigned(L,a,d) \
+ ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d)))
+
+#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
+#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
+
+#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
+#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
+
+#endif
+/* }============================================================ */
+
+
+
+#endif
+
+
diff --git a/src/external/lua/include/lua.h b/src/external/lua/include/lua.h
new file mode 100644
index 00000000..f78899fc
--- /dev/null
+++ b/src/external/lua/include/lua.h
@@ -0,0 +1,486 @@
+/*
+** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $
+** Lua - A Scripting Language
+** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
+** See Copyright Notice at the end of this file
+*/
+
+
+#ifndef lua_h
+#define lua_h
+
+#include <stdarg.h>
+#include <stddef.h>
+
+
+#include "luaconf.h"
+
+
+#define LUA_VERSION_MAJOR "5"
+#define LUA_VERSION_MINOR "3"
+#define LUA_VERSION_NUM 503
+#define LUA_VERSION_RELEASE "3"
+
+#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
+#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2016 Lua.org, PUC-Rio"
+#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
+
+
+/* mark for precompiled code ('<esc>Lua') */
+#define LUA_SIGNATURE "\x1bLua"
+
+/* option for multiple returns in 'lua_pcall' and 'lua_call' */
+#define LUA_MULTRET (-1)
+
+
+/*
+** Pseudo-indices
+** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
+** space after that to help overflow detection)
+*/
+#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
+#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
+
+
+/* thread status */
+#define LUA_OK 0
+#define LUA_YIELD 1
+#define LUA_ERRRUN 2
+#define LUA_ERRSYNTAX 3
+#define LUA_ERRMEM 4
+#define LUA_ERRGCMM 5
+#define LUA_ERRERR 6
+
+
+typedef struct lua_State lua_State;
+
+
+/*
+** basic types
+*/
+#define LUA_TNONE (-1)
+
+#define LUA_TNIL 0
+#define LUA_TBOOLEAN 1
+#define LUA_TLIGHTUSERDATA 2
+#define LUA_TNUMBER 3
+#define LUA_TSTRING 4
+#define LUA_TTABLE 5
+#define LUA_TFUNCTION 6
+#define LUA_TUSERDATA 7
+#define LUA_TTHREAD 8
+
+#define LUA_NUMTAGS 9
+
+
+
+/* minimum Lua stack available to a C function */
+#define LUA_MINSTACK 20
+
+
+/* predefined values in the registry */
+#define LUA_RIDX_MAINTHREAD 1
+#define LUA_RIDX_GLOBALS 2
+#define LUA_RIDX_LAST LUA_RIDX_GLOBALS
+
+
+/* type of numbers in Lua */
+typedef LUA_NUMBER lua_Number;
+
+
+/* type for integer functions */
+typedef LUA_INTEGER lua_Integer;
+
+/* unsigned integer type */
+typedef LUA_UNSIGNED lua_Unsigned;
+
+/* type for continuation-function contexts */
+typedef LUA_KCONTEXT lua_KContext;
+
+
+/*
+** Type for C functions registered with Lua
+*/
+typedef int (*lua_CFunction) (lua_State *L);
+
+/*
+** Type for continuation functions
+*/
+typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
+
+
+/*
+** Type for functions that read/write blocks when loading/dumping Lua chunks
+*/
+typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
+
+typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud);
+
+
+/*
+** Type for memory-allocation functions
+*/
+typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
+
+
+
+/*
+** generic extra include file
+*/
+#if defined(LUA_USER_H)
+#include LUA_USER_H
+#endif
+
+
+/*
+** RCS ident string
+*/
+extern const char lua_ident[];
+
+
+/*
+** state manipulation
+*/
+LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
+LUA_API void (lua_close) (lua_State *L);
+LUA_API lua_State *(lua_newthread) (lua_State *L);
+
+LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
+
+
+LUA_API const lua_Number *(lua_version) (lua_State *L);
+
+
+/*
+** basic stack manipulation
+*/
+LUA_API int (lua_absindex) (lua_State *L, int idx);
+LUA_API int (lua_gettop) (lua_State *L);
+LUA_API void (lua_settop) (lua_State *L, int idx);
+LUA_API void (lua_pushvalue) (lua_State *L, int idx);
+LUA_API void (lua_rotate) (lua_State *L, int idx, int n);
+LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx);
+LUA_API int (lua_checkstack) (lua_State *L, int n);
+
+LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
+
+
+/*
+** access functions (stack -> C)
+*/
+
+LUA_API int (lua_isnumber) (lua_State *L, int idx);
+LUA_API int (lua_isstring) (lua_State *L, int idx);
+LUA_API int (lua_iscfunction) (lua_State *L, int idx);
+LUA_API int (lua_isinteger) (lua_State *L, int idx);
+LUA_API int (lua_isuserdata) (lua_State *L, int idx);
+LUA_API int (lua_type) (lua_State *L, int idx);
+LUA_API const char *(lua_typename) (lua_State *L, int tp);
+
+LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
+LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
+LUA_API int (lua_toboolean) (lua_State *L, int idx);
+LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
+LUA_API size_t (lua_rawlen) (lua_State *L, int idx);
+LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
+LUA_API void *(lua_touserdata) (lua_State *L, int idx);
+LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
+LUA_API const void *(lua_topointer) (lua_State *L, int idx);
+
+
+/*
+** Comparison and arithmetic functions
+*/
+
+#define LUA_OPADD 0 /* ORDER TM, ORDER OP */
+#define LUA_OPSUB 1
+#define LUA_OPMUL 2
+#define LUA_OPMOD 3
+#define LUA_OPPOW 4
+#define LUA_OPDIV 5
+#define LUA_OPIDIV 6
+#define LUA_OPBAND 7
+#define LUA_OPBOR 8
+#define LUA_OPBXOR 9
+#define LUA_OPSHL 10
+#define LUA_OPSHR 11
+#define LUA_OPUNM 12
+#define LUA_OPBNOT 13
+
+LUA_API void (lua_arith) (lua_State *L, int op);
+
+#define LUA_OPEQ 0
+#define LUA_OPLT 1
+#define LUA_OPLE 2
+
+LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
+LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op);
+
+
+/*
+** push functions (C -> stack)
+*/
+LUA_API void (lua_pushnil) (lua_State *L);
+LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
+LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
+LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
+LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
+LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
+ va_list argp);
+LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
+LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
+LUA_API void (lua_pushboolean) (lua_State *L, int b);
+LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
+LUA_API int (lua_pushthread) (lua_State *L);
+
+
+/*
+** get functions (Lua -> stack)
+*/
+LUA_API int (lua_getglobal) (lua_State *L, const char *name);
+LUA_API int (lua_gettable) (lua_State *L, int idx);
+LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);
+LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n);
+LUA_API int (lua_rawget) (lua_State *L, int idx);
+LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
+LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);
+
+LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
+LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
+LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
+LUA_API int (lua_getuservalue) (lua_State *L, int idx);
+
+
+/*
+** set functions (stack -> Lua)
+*/
+LUA_API void (lua_setglobal) (lua_State *L, const char *name);
+LUA_API void (lua_settable) (lua_State *L, int idx);
+LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
+LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n);
+LUA_API void (lua_rawset) (lua_State *L, int idx);
+LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n);
+LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p);
+LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
+LUA_API void (lua_setuservalue) (lua_State *L, int idx);
+
+
+/*
+** 'load' and 'call' functions (load and run Lua code)
+*/
+LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults,
+ lua_KContext ctx, lua_KFunction k);
+#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
+
+LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
+ lua_KContext ctx, lua_KFunction k);
+#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
+
+LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
+ const char *chunkname, const char *mode);
+
+LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
+
+
+/*
+** coroutine functions
+*/
+LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx,
+ lua_KFunction k);
+LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg);
+LUA_API int (lua_status) (lua_State *L);
+LUA_API int (lua_isyieldable) (lua_State *L);
+
+#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
+
+
+/*
+** garbage-collection function and options
+*/
+
+#define LUA_GCSTOP 0
+#define LUA_GCRESTART 1
+#define LUA_GCCOLLECT 2
+#define LUA_GCCOUNT 3
+#define LUA_GCCOUNTB 4
+#define LUA_GCSTEP 5
+#define LUA_GCSETPAUSE 6
+#define LUA_GCSETSTEPMUL 7
+#define LUA_GCISRUNNING 9
+
+LUA_API int (lua_gc) (lua_State *L, int what, int data);
+
+
+/*
+** miscellaneous functions
+*/
+
+LUA_API int (lua_error) (lua_State *L);
+
+LUA_API int (lua_next) (lua_State *L, int idx);
+
+LUA_API void (lua_concat) (lua_State *L, int n);
+LUA_API void (lua_len) (lua_State *L, int idx);
+
+LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
+
+LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
+LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
+
+
+
+/*
+** {==============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE))
+
+#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL)
+#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL)
+
+#define lua_pop(L,n) lua_settop(L, -(n)-1)
+
+#define lua_newtable(L) lua_createtable(L, 0, 0)
+
+#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
+
+#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
+
+#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
+#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
+#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
+#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
+#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
+#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
+#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
+#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
+
+#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
+
+#define lua_pushglobaltable(L) \
+ ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
+
+#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
+
+
+#define lua_insert(L,idx) lua_rotate(L, (idx), 1)
+
+#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))
+
+#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1))
+
+/* }============================================================== */
+
+
+/*
+** {==============================================================
+** compatibility macros for unsigned conversions
+** ===============================================================
+*/
+#if defined(LUA_COMPAT_APIINTCASTS)
+
+#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
+#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is))
+#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL)
+
+#endif
+/* }============================================================== */
+
+/*
+** {======================================================================
+** Debug API
+** =======================================================================
+*/
+
+
+/*
+** Event codes
+*/
+#define LUA_HOOKCALL 0
+#define LUA_HOOKRET 1
+#define LUA_HOOKLINE 2
+#define LUA_HOOKCOUNT 3
+#define LUA_HOOKTAILCALL 4
+
+
+/*
+** Event masks
+*/
+#define LUA_MASKCALL (1 << LUA_HOOKCALL)
+#define LUA_MASKRET (1 << LUA_HOOKRET)
+#define LUA_MASKLINE (1 << LUA_HOOKLINE)
+#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
+
+typedef struct lua_Debug lua_Debug; /* activation record */
+
+
+/* Functions to be called by the debugger in specific events */
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
+
+
+LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
+LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
+LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n);
+LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n);
+
+LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n);
+LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1,
+ int fidx2, int n2);
+
+LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);
+LUA_API lua_Hook (lua_gethook) (lua_State *L);
+LUA_API int (lua_gethookmask) (lua_State *L);
+LUA_API int (lua_gethookcount) (lua_State *L);
+
+
+struct lua_Debug {
+ int event;
+ const char *name; /* (n) */
+ const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */
+ const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */
+ const char *source; /* (S) */
+ int currentline; /* (l) */
+ int linedefined; /* (S) */
+ int lastlinedefined; /* (S) */
+ unsigned char nups; /* (u) number of upvalues */
+ unsigned char nparams;/* (u) number of parameters */
+ char isvararg; /* (u) */
+ char istailcall; /* (t) */
+ char short_src[LUA_IDSIZE]; /* (S) */
+ /* private part */
+ struct CallInfo *i_ci; /* active function */
+};
+
+/* }====================================================================== */
+
+
+/******************************************************************************
+* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
+*
+* 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.
+******************************************************************************/
+
+
+#endif
diff --git a/src/external/lua/include/lua.hpp b/src/external/lua/include/lua.hpp
new file mode 100644
index 00000000..ec417f59
--- /dev/null
+++ b/src/external/lua/include/lua.hpp
@@ -0,0 +1,9 @@
+// lua.hpp
+// Lua header files for C++
+// <<extern "C">> not supplied automatically because Lua also compiles as C++
+
+extern "C" {
+#include "lua.h"
+#include "lualib.h"
+#include "lauxlib.h"
+}
diff --git a/src/external/lua/include/luaconf.h b/src/external/lua/include/luaconf.h
new file mode 100644
index 00000000..867e9cb1
--- /dev/null
+++ b/src/external/lua/include/luaconf.h
@@ -0,0 +1,769 @@
+/*
+** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $
+** Configuration file for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef luaconf_h
+#define luaconf_h
+
+#include <limits.h>
+#include <stddef.h>
+
+
+/*
+** ===================================================================
+** Search for "@@" to find all configurable definitions.
+** ===================================================================
+*/
+
+
+/*
+** {====================================================================
+** System Configuration: macros to adapt (if needed) Lua to some
+** particular platform, for instance compiling it with 32-bit numbers or
+** restricting it to C89.
+** =====================================================================
+*/
+
+/*
+@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You
+** can also define LUA_32BITS in the make file, but changing here you
+** ensure that all software connected to Lua will be compiled with the
+** same configuration.
+*/
+/* #define LUA_32BITS */
+
+
+/*
+@@ LUA_USE_C89 controls the use of non-ISO-C89 features.
+** Define it if you want Lua to avoid the use of a few C99 features
+** or Windows-specific features on Windows.
+*/
+/* #define LUA_USE_C89 */
+
+
+/*
+** By default, Lua on Windows use (some) specific Windows features
+*/
+#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE)
+#define LUA_USE_WINDOWS /* enable goodies for regular Windows */
+#endif
+
+
+#if defined(LUA_USE_WINDOWS)
+#define LUA_DL_DLL /* enable support for DLL */
+#define LUA_USE_C89 /* broadly, Windows is C89 */
+#endif
+
+
+#if defined(LUA_USE_LINUX)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
+#define LUA_USE_READLINE /* needs some extra libraries */
+#endif
+
+
+#if defined(LUA_USE_MACOSX)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN /* MacOS does not need -ldl */
+#define LUA_USE_READLINE /* needs an extra library: -lreadline */
+#endif
+
+
+/*
+@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
+** C89 ('long' and 'double'); Windows always has '__int64', so it does
+** not need to use this case.
+*/
+#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
+#define LUA_C89_NUMBERS
+#endif
+
+
+
+/*
+@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'.
+*/
+/* avoid undefined shifts */
+#if ((INT_MAX >> 15) >> 15) >= 1
+#define LUAI_BITSINT 32
+#else
+/* 'int' always must have at least 16 bits */
+#define LUAI_BITSINT 16
+#endif
+
+
+/*
+@@ LUA_INT_TYPE defines the type for Lua integers.
+@@ LUA_FLOAT_TYPE defines the type for Lua floats.
+** Lua should work fine with any mix of these options (if supported
+** by your C compiler). The usual configurations are 64-bit integers
+** and 'double' (the default), 32-bit integers and 'float' (for
+** restricted platforms), and 'long'/'double' (for C compilers not
+** compliant with C99, which may not have support for 'long long').
+*/
+
+/* predefined options for LUA_INT_TYPE */
+#define LUA_INT_INT 1
+#define LUA_INT_LONG 2
+#define LUA_INT_LONGLONG 3
+
+/* predefined options for LUA_FLOAT_TYPE */
+#define LUA_FLOAT_FLOAT 1
+#define LUA_FLOAT_DOUBLE 2
+#define LUA_FLOAT_LONGDOUBLE 3
+
+#if defined(LUA_32BITS) /* { */
+/*
+** 32-bit integers and 'float'
+*/
+#if LUAI_BITSINT >= 32 /* use 'int' if big enough */
+#define LUA_INT_TYPE LUA_INT_INT
+#else /* otherwise use 'long' */
+#define LUA_INT_TYPE LUA_INT_LONG
+#endif
+#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
+
+#elif defined(LUA_C89_NUMBERS) /* }{ */
+/*
+** largest types available for C89 ('long' and 'double')
+*/
+#define LUA_INT_TYPE LUA_INT_LONG
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+
+#endif /* } */
+
+
+/*
+** default configuration for 64-bit Lua ('long long' and 'double')
+*/
+#if !defined(LUA_INT_TYPE)
+#define LUA_INT_TYPE LUA_INT_LONGLONG
+#endif
+
+#if !defined(LUA_FLOAT_TYPE)
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+#endif
+
+/* }================================================================== */
+
+
+
+
+/*
+** {==================================================================
+** Configuration for Paths.
+** ===================================================================
+*/
+
+/*
+@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
+** Lua libraries.
+@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
+** C libraries.
+** CHANGE them if your machine has a non-conventional directory
+** hierarchy or if you want to install your libraries in
+** non-conventional directories.
+*/
+#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
+#if defined(_WIN32) /* { */
+/*
+** In Windows, any exclamation mark ('!') in the path is replaced by the
+** path of the directory of the executable file of the current process.
+*/
+#define LUA_LDIR "!\\lua\\"
+#define LUA_CDIR "!\\"
+#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\"
+#define LUA_PATH_DEFAULT \
+ LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \
+ LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \
+ ".\\?.lua;" ".\\?\\init.lua"
+#define LUA_CPATH_DEFAULT \
+ LUA_CDIR"?.dll;" \
+ LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
+ LUA_CDIR"loadall.dll;" ".\\?.dll;" \
+ LUA_CDIR"?53.dll;" ".\\?53.dll"
+
+#else /* }{ */
+
+#define LUA_ROOT "/usr/local/"
+#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/"
+#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/"
+#define LUA_PATH_DEFAULT \
+ LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
+ "./?.lua;" "./?/init.lua"
+#define LUA_CPATH_DEFAULT \
+ LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so;" \
+ LUA_CDIR"lib?53.so;" "./lib?53.so"
+#endif /* } */
+
+
+/*
+@@ LUA_DIRSEP is the directory separator (for submodules).
+** CHANGE it if your machine does not use "/" as the directory separator
+** and is not Windows. (On Windows Lua automatically uses "\".)
+*/
+#if defined(_WIN32)
+#define LUA_DIRSEP "\\"
+#else
+#define LUA_DIRSEP "/"
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Marks for exported symbols in the C code
+** ===================================================================
+*/
+
+/*
+@@ LUA_API is a mark for all core API functions.
+@@ LUALIB_API is a mark for all auxiliary library functions.
+@@ LUAMOD_API is a mark for all standard library opening functions.
+** CHANGE them if you need to define those functions in some special way.
+** For instance, if you want to create one Windows DLL with the core and
+** the libraries, you may want to use the following definition (define
+** LUA_BUILD_AS_DLL to get it).
+*/
+#if defined(LUA_BUILD_AS_DLL) /* { */
+
+#if defined(LUA_CORE) || defined(LUA_LIB) /* { */
+#define LUA_API __declspec(dllexport)
+#else /* }{ */
+#define LUA_API __declspec(dllimport)
+#endif /* } */
+
+#else /* }{ */
+
+#define LUA_API extern
+
+#endif /* } */
+
+
+/* more often than not the libs go together with the core */
+#define LUALIB_API LUA_API
+#define LUAMOD_API LUALIB_API
+
+
+/*
+@@ LUAI_FUNC is a mark for all extern functions that are not to be
+** exported to outside modules.
+@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables
+** that are not to be exported to outside modules (LUAI_DDEF for
+** definitions and LUAI_DDEC for declarations).
+** CHANGE them if you need to mark them in some special way. Elf/gcc
+** (versions 3.2 and later) mark them as "hidden" to optimize access
+** when Lua is compiled as a shared library. Not all elf targets support
+** this attribute. Unfortunately, gcc does not offer a way to check
+** whether the target offers that support, and those without support
+** give a warning about it. To avoid these warnings, change to the
+** default definition.
+*/
+#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
+ defined(__ELF__) /* { */
+#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
+#else /* }{ */
+#define LUAI_FUNC extern
+#endif /* } */
+
+#define LUAI_DDEC LUAI_FUNC
+#define LUAI_DDEF /* empty */
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Compatibility with previous versions
+** ===================================================================
+*/
+
+/*
+@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2.
+@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1.
+** You can define it to get all options, or change specific options
+** to fit your specific needs.
+*/
+#if defined(LUA_COMPAT_5_2) /* { */
+
+/*
+@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
+** functions in the mathematical library.
+*/
+#define LUA_COMPAT_MATHLIB
+
+/*
+@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'.
+*/
+#define LUA_COMPAT_BITLIB
+
+/*
+@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod.
+*/
+#define LUA_COMPAT_IPAIRS
+
+/*
+@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for
+** manipulating other integer types (lua_pushunsigned, lua_tounsigned,
+** luaL_checkint, luaL_checklong, etc.)
+*/
+#define LUA_COMPAT_APIINTCASTS
+
+#endif /* } */
+
+
+#if defined(LUA_COMPAT_5_1) /* { */
+
+/* Incompatibilities from 5.2 -> 5.3 */
+#define LUA_COMPAT_MATHLIB
+#define LUA_COMPAT_APIINTCASTS
+
+/*
+@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
+** You can replace it with 'table.unpack'.
+*/
+#define LUA_COMPAT_UNPACK
+
+/*
+@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'.
+** You can replace it with 'package.searchers'.
+*/
+#define LUA_COMPAT_LOADERS
+
+/*
+@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall.
+** You can call your C function directly (with light C functions).
+*/
+#define lua_cpcall(L,f,u) \
+ (lua_pushcfunction(L, (f)), \
+ lua_pushlightuserdata(L,(u)), \
+ lua_pcall(L,1,0,0))
+
+
+/*
+@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library.
+** You can rewrite 'log10(x)' as 'log(x, 10)'.
+*/
+#define LUA_COMPAT_LOG10
+
+/*
+@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base
+** library. You can rewrite 'loadstring(s)' as 'load(s)'.
+*/
+#define LUA_COMPAT_LOADSTRING
+
+/*
+@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library.
+*/
+#define LUA_COMPAT_MAXN
+
+/*
+@@ The following macros supply trivial compatibility for some
+** changes in the API. The macros themselves document how to
+** change your code to avoid using them.
+*/
+#define lua_strlen(L,i) lua_rawlen(L, (i))
+
+#define lua_objlen(L,i) lua_rawlen(L, (i))
+
+#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
+#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
+
+/*
+@@ LUA_COMPAT_MODULE controls compatibility with previous
+** module functions 'module' (Lua) and 'luaL_register' (C).
+*/
+#define LUA_COMPAT_MODULE
+
+#endif /* } */
+
+
+/*
+@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
+@@ a float mark ('.0').
+** This macro is not on by default even in compatibility mode,
+** because this is not really an incompatibility.
+*/
+/* #define LUA_COMPAT_FLOATSTRING */
+
+/* }================================================================== */
+
+
+
+/*
+** {==================================================================
+** Configuration for Numbers.
+** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
+** satisfy your needs.
+** ===================================================================
+*/
+
+/*
+@@ LUA_NUMBER is the floating-point type used by Lua.
+@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
+@@ over a floating number.
+@@ l_mathlim(x) corrects limit name 'x' to the proper float type
+** by prefixing it with one of FLT/DBL/LDBL.
+@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
+@@ LUA_NUMBER_FMT is the format for writing floats.
+@@ lua_number2str converts a float to a string.
+@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
+@@ l_floor takes the floor of a float.
+@@ lua_str2number converts a decimal numeric string to a number.
+*/
+
+
+/* The following definitions are good for most cases here */
+
+#define l_floor(x) (l_mathop(floor)(x))
+
+#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n))
+
+/*
+@@ lua_numbertointeger converts a float number to an integer, or
+** returns 0 if float is not within the range of a lua_Integer.
+** (The range comparisons are tricky because of rounding. The tests
+** here assume a two-complement representation, where MININTEGER always
+** has an exact representation as a float; MAXINTEGER may not have one,
+** and therefore its conversion to float may have an ill-defined value.)
+*/
+#define lua_numbertointeger(n,p) \
+ ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
+ (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
+ (*(p) = (LUA_INTEGER)(n), 1))
+
+
+/* now the variable definitions */
+
+#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
+
+#define LUA_NUMBER float
+
+#define l_mathlim(n) (FLT_##n)
+
+#define LUAI_UACNUMBER double
+
+#define LUA_NUMBER_FRMLEN ""
+#define LUA_NUMBER_FMT "%.7g"
+
+#define l_mathop(op) op##f
+
+#define lua_str2number(s,p) strtof((s), (p))
+
+
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */
+
+#define LUA_NUMBER long double
+
+#define l_mathlim(n) (LDBL_##n)
+
+#define LUAI_UACNUMBER long double
+
+#define LUA_NUMBER_FRMLEN "L"
+#define LUA_NUMBER_FMT "%.19Lg"
+
+#define l_mathop(op) op##l
+
+#define lua_str2number(s,p) strtold((s), (p))
+
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */
+
+#define LUA_NUMBER double
+
+#define l_mathlim(n) (DBL_##n)
+
+#define LUAI_UACNUMBER double
+
+#define LUA_NUMBER_FRMLEN ""
+#define LUA_NUMBER_FMT "%.14g"
+
+#define l_mathop(op) op
+
+#define lua_str2number(s,p) strtod((s), (p))
+
+#else /* }{ */
+
+#error "numeric float type not defined"
+
+#endif /* } */
+
+
+
+/*
+@@ LUA_INTEGER is the integer type used by Lua.
+**
+@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
+**
+@@ LUAI_UACINT is the result of an 'usual argument conversion'
+@@ over a lUA_INTEGER.
+@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
+@@ LUA_INTEGER_FMT is the format for writing integers.
+@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
+@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
+@@ lua_integer2str converts an integer to a string.
+*/
+
+
+/* The following definitions are good for most cases here */
+
+#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
+#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n))
+
+#define LUAI_UACINT LUA_INTEGER
+
+/*
+** use LUAI_UACINT here to avoid problems with promotions (which
+** can turn a comparison between unsigneds into a signed comparison)
+*/
+#define LUA_UNSIGNED unsigned LUAI_UACINT
+
+
+/* now the variable definitions */
+
+#if LUA_INT_TYPE == LUA_INT_INT /* { int */
+
+#define LUA_INTEGER int
+#define LUA_INTEGER_FRMLEN ""
+
+#define LUA_MAXINTEGER INT_MAX
+#define LUA_MININTEGER INT_MIN
+
+#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */
+
+#define LUA_INTEGER long
+#define LUA_INTEGER_FRMLEN "l"
+
+#define LUA_MAXINTEGER LONG_MAX
+#define LUA_MININTEGER LONG_MIN
+
+#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
+
+/* use presence of macro LLONG_MAX as proxy for C99 compliance */
+#if defined(LLONG_MAX) /* { */
+/* use ISO C99 stuff */
+
+#define LUA_INTEGER long long
+#define LUA_INTEGER_FRMLEN "ll"
+
+#define LUA_MAXINTEGER LLONG_MAX
+#define LUA_MININTEGER LLONG_MIN
+
+#elif defined(LUA_USE_WINDOWS) /* }{ */
+/* in Windows, can use specific Windows types */
+
+#define LUA_INTEGER __int64
+#define LUA_INTEGER_FRMLEN "I64"
+
+#define LUA_MAXINTEGER _I64_MAX
+#define LUA_MININTEGER _I64_MIN
+
+#else /* }{ */
+
+#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \
+ or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)"
+
+#endif /* } */
+
+#else /* }{ */
+
+#error "numeric integer type not defined"
+
+#endif /* } */
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Dependencies with C99 and other C details
+** ===================================================================
+*/
+
+/*
+@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
+** (All uses in Lua have only one format item.)
+*/
+#if !defined(LUA_USE_C89)
+#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
+#else
+#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
+#endif
+
+
+/*
+@@ lua_strx2number converts an hexadecimal numeric string to a number.
+** In C99, 'strtod' does that conversion. Otherwise, you can
+** leave 'lua_strx2number' undefined and Lua will provide its own
+** implementation.
+*/
+#if !defined(LUA_USE_C89)
+#define lua_strx2number(s,p) lua_str2number(s,p)
+#endif
+
+
+/*
+@@ lua_number2strx converts a float to an hexadecimal numeric string.
+** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
+** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
+** provide its own implementation.
+*/
+#if !defined(LUA_USE_C89)
+#define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n))
+#endif
+
+
+/*
+** 'strtof' and 'opf' variants for math functions are not valid in
+** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the
+** availability of these variants. ('math.h' is already included in
+** all files that use these macros.)
+*/
+#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF))
+#undef l_mathop /* variants not available */
+#undef lua_str2number
+#define l_mathop(op) (lua_Number)op /* no variant */
+#define lua_str2number(s,p) ((lua_Number)strtod((s), (p)))
+#endif
+
+
+/*
+@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation
+** functions. It must be a numerical type; Lua will use 'intptr_t' if
+** available, otherwise it will use 'ptrdiff_t' (the nearest thing to
+** 'intptr_t' in C89)
+*/
+#define LUA_KCONTEXT ptrdiff_t
+
+#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
+ __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+#if defined(INTPTR_MAX) /* even in C99 this type is optional */
+#undef LUA_KCONTEXT
+#define LUA_KCONTEXT intptr_t
+#endif
+#endif
+
+
+/*
+@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point).
+** Change that if you do not want to use C locales. (Code using this
+** macro must include header 'locale.h'.)
+*/
+#if !defined(lua_getlocaledecpoint)
+#define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Language Variations
+** =====================================================================
+*/
+
+/*
+@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some
+** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from
+** numbers to strings. Define LUA_NOCVTS2N to turn off automatic
+** coercion from strings to numbers.
+*/
+/* #define LUA_NOCVTN2S */
+/* #define LUA_NOCVTS2N */
+
+
+/*
+@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
+** Define it as a help when debugging C code.
+*/
+#if defined(LUA_USE_APICHECK)
+#include <assert.h>
+#define luai_apicheck(l,e) assert(e)
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Macros that affect the API and must be stable (that is, must be the
+** same when you compile Lua and when you compile code that links to
+** Lua). You probably do not want/need to change them.
+** =====================================================================
+*/
+
+/*
+@@ LUAI_MAXSTACK limits the size of the Lua stack.
+** CHANGE it if you need a different limit. This limit is arbitrary;
+** its only purpose is to stop Lua from consuming unlimited stack
+** space (and to reserve some numbers for pseudo-indices).
+*/
+#if LUAI_BITSINT >= 32
+#define LUAI_MAXSTACK 1000000
+#else
+#define LUAI_MAXSTACK 15000
+#endif
+
+
+/*
+@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
+** a Lua state with very fast access.
+** CHANGE it if you need a different size.
+*/
+#define LUA_EXTRASPACE (sizeof(void *))
+
+
+/*
+@@ LUA_IDSIZE gives the maximum size for the description of the source
+@@ of a function in debug information.
+** CHANGE it if you want a different size.
+*/
+#define LUA_IDSIZE 60
+
+
+/*
+@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+** CHANGE it if it uses too much C-stack space. (For long double,
+** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a
+** smaller buffer would force a memory allocation for each call to
+** 'string.format'.)
+*/
+#if defined(LUA_FLOAT_LONGDOUBLE)
+#define LUAL_BUFFERSIZE 8192
+#else
+#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
+#endif
+
+/* }================================================================== */
+
+
+/*
+@@ LUA_QL describes how error messages quote program elements.
+** Lua does not use these macros anymore; they are here for
+** compatibility only.
+*/
+#define LUA_QL(x) "'" x "'"
+#define LUA_QS LUA_QL("%s")
+
+
+
+
+/* =================================================================== */
+
+/*
+** Local configuration. You can use this space to add your redefinitions
+** without modifying the main part of the file.
+*/
+
+
+
+
+
+#endif
+
diff --git a/src/external/lua/include/lualib.h b/src/external/lua/include/lualib.h
new file mode 100644
index 00000000..5165c0fb
--- /dev/null
+++ b/src/external/lua/include/lualib.h
@@ -0,0 +1,58 @@
+/*
+** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $
+** Lua standard libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lualib_h
+#define lualib_h
+
+#include "lua.h"
+
+
+
+LUAMOD_API int (luaopen_base) (lua_State *L);
+
+#define LUA_COLIBNAME "coroutine"
+LUAMOD_API int (luaopen_coroutine) (lua_State *L);
+
+#define LUA_TABLIBNAME "table"
+LUAMOD_API int (luaopen_table) (lua_State *L);
+
+#define LUA_IOLIBNAME "io"
+LUAMOD_API int (luaopen_io) (lua_State *L);
+
+#define LUA_OSLIBNAME "os"
+LUAMOD_API int (luaopen_os) (lua_State *L);
+
+#define LUA_STRLIBNAME "string"
+LUAMOD_API int (luaopen_string) (lua_State *L);
+
+#define LUA_UTF8LIBNAME "utf8"
+LUAMOD_API int (luaopen_utf8) (lua_State *L);
+
+#define LUA_BITLIBNAME "bit32"
+LUAMOD_API int (luaopen_bit32) (lua_State *L);
+
+#define LUA_MATHLIBNAME "math"
+LUAMOD_API int (luaopen_math) (lua_State *L);
+
+#define LUA_DBLIBNAME "debug"
+LUAMOD_API int (luaopen_debug) (lua_State *L);
+
+#define LUA_LOADLIBNAME "package"
+LUAMOD_API int (luaopen_package) (lua_State *L);
+
+
+/* open all previous libraries */
+LUALIB_API void (luaL_openlibs) (lua_State *L);
+
+
+
+#if !defined(lua_assert)
+#define lua_assert(x) ((void)0)
+#endif
+
+
+#endif
diff --git a/src/external/lua/lib/liblua53.a b/src/external/lua/lib/liblua53.a
new file mode 100644
index 00000000..e51c0c80
--- /dev/null
+++ b/src/external/lua/lib/liblua53.a
Binary files differ
diff --git a/src/external/lua/lib/liblua53dll.a b/src/external/lua/lib/liblua53dll.a
new file mode 100644
index 00000000..32646db3
--- /dev/null
+++ b/src/external/lua/lib/liblua53dll.a
Binary files differ
diff --git a/src/external/openal_soft/COPYING b/src/external/openal_soft/COPYING
new file mode 100644
index 00000000..d0c89786
--- /dev/null
+++ b/src/external/openal_soft/COPYING
@@ -0,0 +1,484 @@
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
diff --git a/src/external/openal_soft/include/AL/al.h b/src/external/openal_soft/include/AL/al.h
new file mode 100644
index 00000000..413b3833
--- /dev/null
+++ b/src/external/openal_soft/include/AL/al.h
@@ -0,0 +1,656 @@
+#ifndef AL_AL_H
+#define AL_AL_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef AL_API
+ #if defined(AL_LIBTYPE_STATIC)
+ #define AL_API
+ #elif defined(_WIN32)
+ #define AL_API __declspec(dllimport)
+ #else
+ #define AL_API extern
+ #endif
+#endif
+
+#if defined(_WIN32)
+ #define AL_APIENTRY __cdecl
+#else
+ #define AL_APIENTRY
+#endif
+
+
+/** Deprecated macro. */
+#define OPENAL
+#define ALAPI AL_API
+#define ALAPIENTRY AL_APIENTRY
+#define AL_INVALID (-1)
+#define AL_ILLEGAL_ENUM AL_INVALID_ENUM
+#define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION
+
+/** Supported AL version. */
+#define AL_VERSION_1_0
+#define AL_VERSION_1_1
+
+/** 8-bit boolean */
+typedef char ALboolean;
+
+/** character */
+typedef char ALchar;
+
+/** signed 8-bit 2's complement integer */
+typedef signed char ALbyte;
+
+/** unsigned 8-bit integer */
+typedef unsigned char ALubyte;
+
+/** signed 16-bit 2's complement integer */
+typedef short ALshort;
+
+/** unsigned 16-bit integer */
+typedef unsigned short ALushort;
+
+/** signed 32-bit 2's complement integer */
+typedef int ALint;
+
+/** unsigned 32-bit integer */
+typedef unsigned int ALuint;
+
+/** non-negative 32-bit binary integer size */
+typedef int ALsizei;
+
+/** enumerated 32-bit value */
+typedef int ALenum;
+
+/** 32-bit IEEE754 floating-point */
+typedef float ALfloat;
+
+/** 64-bit IEEE754 floating-point */
+typedef double ALdouble;
+
+/** void type (for opaque pointers only) */
+typedef void ALvoid;
+
+
+/* Enumerant values begin at column 50. No tabs. */
+
+/** "no distance model" or "no buffer" */
+#define AL_NONE 0
+
+/** Boolean False. */
+#define AL_FALSE 0
+
+/** Boolean True. */
+#define AL_TRUE 1
+
+
+/**
+ * Relative source.
+ * Type: ALboolean
+ * Range: [AL_TRUE, AL_FALSE]
+ * Default: AL_FALSE
+ *
+ * Specifies if the Source has relative coordinates.
+ */
+#define AL_SOURCE_RELATIVE 0x202
+
+
+/**
+ * Inner cone angle, in degrees.
+ * Type: ALint, ALfloat
+ * Range: [0 - 360]
+ * Default: 360
+ *
+ * The angle covered by the inner cone, where the source will not attenuate.
+ */
+#define AL_CONE_INNER_ANGLE 0x1001
+
+/**
+ * Outer cone angle, in degrees.
+ * Range: [0 - 360]
+ * Default: 360
+ *
+ * The angle covered by the outer cone, where the source will be fully
+ * attenuated.
+ */
+#define AL_CONE_OUTER_ANGLE 0x1002
+
+/**
+ * Source pitch.
+ * Type: ALfloat
+ * Range: [0.5 - 2.0]
+ * Default: 1.0
+ *
+ * A multiplier for the frequency (sample rate) of the source's buffer.
+ */
+#define AL_PITCH 0x1003
+
+/**
+ * Source or listener position.
+ * Type: ALfloat[3], ALint[3]
+ * Default: {0, 0, 0}
+ *
+ * The source or listener location in three dimensional space.
+ *
+ * OpenAL, like OpenGL, uses a right handed coordinate system, where in a
+ * frontal default view X (thumb) points right, Y points up (index finger), and
+ * Z points towards the viewer/camera (middle finger).
+ *
+ * To switch from a left handed coordinate system, flip the sign on the Z
+ * coordinate.
+ */
+#define AL_POSITION 0x1004
+
+/**
+ * Source direction.
+ * Type: ALfloat[3], ALint[3]
+ * Default: {0, 0, 0}
+ *
+ * Specifies the current direction in local space.
+ * A zero-length vector specifies an omni-directional source (cone is ignored).
+ */
+#define AL_DIRECTION 0x1005
+
+/**
+ * Source or listener velocity.
+ * Type: ALfloat[3], ALint[3]
+ * Default: {0, 0, 0}
+ *
+ * Specifies the current velocity in local space.
+ */
+#define AL_VELOCITY 0x1006
+
+/**
+ * Source looping.
+ * Type: ALboolean
+ * Range: [AL_TRUE, AL_FALSE]
+ * Default: AL_FALSE
+ *
+ * Specifies whether source is looping.
+ */
+#define AL_LOOPING 0x1007
+
+/**
+ * Source buffer.
+ * Type: ALuint
+ * Range: any valid Buffer.
+ *
+ * Specifies the buffer to provide sound samples.
+ */
+#define AL_BUFFER 0x1009
+
+/**
+ * Source or listener gain.
+ * Type: ALfloat
+ * Range: [0.0 - ]
+ *
+ * A value of 1.0 means unattenuated. Each division by 2 equals an attenuation
+ * of about -6dB. Each multiplicaton by 2 equals an amplification of about
+ * +6dB.
+ *
+ * A value of 0.0 is meaningless with respect to a logarithmic scale; it is
+ * silent.
+ */
+#define AL_GAIN 0x100A
+
+/**
+ * Minimum source gain.
+ * Type: ALfloat
+ * Range: [0.0 - 1.0]
+ *
+ * The minimum gain allowed for a source, after distance and cone attenation is
+ * applied (if applicable).
+ */
+#define AL_MIN_GAIN 0x100D
+
+/**
+ * Maximum source gain.
+ * Type: ALfloat
+ * Range: [0.0 - 1.0]
+ *
+ * The maximum gain allowed for a source, after distance and cone attenation is
+ * applied (if applicable).
+ */
+#define AL_MAX_GAIN 0x100E
+
+/**
+ * Listener orientation.
+ * Type: ALfloat[6]
+ * Default: {0.0, 0.0, -1.0, 0.0, 1.0, 0.0}
+ *
+ * Effectively two three dimensional vectors. The first vector is the front (or
+ * "at") and the second is the top (or "up").
+ *
+ * Both vectors are in local space.
+ */
+#define AL_ORIENTATION 0x100F
+
+/**
+ * Source state (query only).
+ * Type: ALint
+ * Range: [AL_INITIAL, AL_PLAYING, AL_PAUSED, AL_STOPPED]
+ */
+#define AL_SOURCE_STATE 0x1010
+
+/** Source state value. */
+#define AL_INITIAL 0x1011
+#define AL_PLAYING 0x1012
+#define AL_PAUSED 0x1013
+#define AL_STOPPED 0x1014
+
+/**
+ * Source Buffer Queue size (query only).
+ * Type: ALint
+ *
+ * The number of buffers queued using alSourceQueueBuffers, minus the buffers
+ * removed with alSourceUnqueueBuffers.
+ */
+#define AL_BUFFERS_QUEUED 0x1015
+
+/**
+ * Source Buffer Queue processed count (query only).
+ * Type: ALint
+ *
+ * The number of queued buffers that have been fully processed, and can be
+ * removed with alSourceUnqueueBuffers.
+ *
+ * Looping sources will never fully process buffers because they will be set to
+ * play again for when the source loops.
+ */
+#define AL_BUFFERS_PROCESSED 0x1016
+
+/**
+ * Source reference distance.
+ * Type: ALfloat
+ * Range: [0.0 - ]
+ * Default: 1.0
+ *
+ * The distance in units that no attenuation occurs.
+ *
+ * At 0.0, no distance attenuation ever occurs on non-linear attenuation models.
+ */
+#define AL_REFERENCE_DISTANCE 0x1020
+
+/**
+ * Source rolloff factor.
+ * Type: ALfloat
+ * Range: [0.0 - ]
+ * Default: 1.0
+ *
+ * Multiplier to exaggerate or diminish distance attenuation.
+ *
+ * At 0.0, no distance attenuation ever occurs.
+ */
+#define AL_ROLLOFF_FACTOR 0x1021
+
+/**
+ * Outer cone gain.
+ * Type: ALfloat
+ * Range: [0.0 - 1.0]
+ * Default: 0.0
+ *
+ * The gain attenuation applied when the listener is outside of the source's
+ * outer cone.
+ */
+#define AL_CONE_OUTER_GAIN 0x1022
+
+/**
+ * Source maximum distance.
+ * Type: ALfloat
+ * Range: [0.0 - ]
+ * Default: +inf
+ *
+ * The distance above which the source is not attenuated any further with a
+ * clamped distance model, or where attenuation reaches 0.0 gain for linear
+ * distance models with a default rolloff factor.
+ */
+#define AL_MAX_DISTANCE 0x1023
+
+/** Source buffer position, in seconds */
+#define AL_SEC_OFFSET 0x1024
+/** Source buffer position, in sample frames */
+#define AL_SAMPLE_OFFSET 0x1025
+/** Source buffer position, in bytes */
+#define AL_BYTE_OFFSET 0x1026
+
+/**
+ * Source type (query only).
+ * Type: ALint
+ * Range: [AL_STATIC, AL_STREAMING, AL_UNDETERMINED]
+ *
+ * A Source is Static if a Buffer has been attached using AL_BUFFER.
+ *
+ * A Source is Streaming if one or more Buffers have been attached using
+ * alSourceQueueBuffers.
+ *
+ * A Source is Undetermined when it has the NULL buffer attached using
+ * AL_BUFFER.
+ */
+#define AL_SOURCE_TYPE 0x1027
+
+/** Source type value. */
+#define AL_STATIC 0x1028
+#define AL_STREAMING 0x1029
+#define AL_UNDETERMINED 0x1030
+
+/** Buffer format specifier. */
+#define AL_FORMAT_MONO8 0x1100
+#define AL_FORMAT_MONO16 0x1101
+#define AL_FORMAT_STEREO8 0x1102
+#define AL_FORMAT_STEREO16 0x1103
+
+/** Buffer frequency (query only). */
+#define AL_FREQUENCY 0x2001
+/** Buffer bits per sample (query only). */
+#define AL_BITS 0x2002
+/** Buffer channel count (query only). */
+#define AL_CHANNELS 0x2003
+/** Buffer data size (query only). */
+#define AL_SIZE 0x2004
+
+/**
+ * Buffer state.
+ *
+ * Not for public use.
+ */
+#define AL_UNUSED 0x2010
+#define AL_PENDING 0x2011
+#define AL_PROCESSED 0x2012
+
+
+/** No error. */
+#define AL_NO_ERROR 0
+
+/** Invalid name paramater passed to AL call. */
+#define AL_INVALID_NAME 0xA001
+
+/** Invalid enum parameter passed to AL call. */
+#define AL_INVALID_ENUM 0xA002
+
+/** Invalid value parameter passed to AL call. */
+#define AL_INVALID_VALUE 0xA003
+
+/** Illegal AL call. */
+#define AL_INVALID_OPERATION 0xA004
+
+/** Not enough memory. */
+#define AL_OUT_OF_MEMORY 0xA005
+
+
+/** Context string: Vendor ID. */
+#define AL_VENDOR 0xB001
+/** Context string: Version. */
+#define AL_VERSION 0xB002
+/** Context string: Renderer ID. */
+#define AL_RENDERER 0xB003
+/** Context string: Space-separated extension list. */
+#define AL_EXTENSIONS 0xB004
+
+
+/**
+ * Doppler scale.
+ * Type: ALfloat
+ * Range: [0.0 - ]
+ * Default: 1.0
+ *
+ * Scale for source and listener velocities.
+ */
+#define AL_DOPPLER_FACTOR 0xC000
+AL_API void AL_APIENTRY alDopplerFactor(ALfloat value);
+
+/**
+ * Doppler velocity (deprecated).
+ *
+ * A multiplier applied to the Speed of Sound.
+ */
+#define AL_DOPPLER_VELOCITY 0xC001
+AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value);
+
+/**
+ * Speed of Sound, in units per second.
+ * Type: ALfloat
+ * Range: [0.0001 - ]
+ * Default: 343.3
+ *
+ * The speed at which sound waves are assumed to travel, when calculating the
+ * doppler effect.
+ */
+#define AL_SPEED_OF_SOUND 0xC003
+AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value);
+
+/**
+ * Distance attenuation model.
+ * Type: ALint
+ * Range: [AL_NONE, AL_INVERSE_DISTANCE, AL_INVERSE_DISTANCE_CLAMPED,
+ * AL_LINEAR_DISTANCE, AL_LINEAR_DISTANCE_CLAMPED,
+ * AL_EXPONENT_DISTANCE, AL_EXPONENT_DISTANCE_CLAMPED]
+ * Default: AL_INVERSE_DISTANCE_CLAMPED
+ *
+ * The model by which sources attenuate with distance.
+ *
+ * None - No distance attenuation.
+ * Inverse - Doubling the distance halves the source gain.
+ * Linear - Linear gain scaling between the reference and max distances.
+ * Exponent - Exponential gain dropoff.
+ *
+ * Clamped variations work like the non-clamped counterparts, except the
+ * distance calculated is clamped between the reference and max distances.
+ */
+#define AL_DISTANCE_MODEL 0xD000
+AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel);
+
+/** Distance model value. */
+#define AL_INVERSE_DISTANCE 0xD001
+#define AL_INVERSE_DISTANCE_CLAMPED 0xD002
+#define AL_LINEAR_DISTANCE 0xD003
+#define AL_LINEAR_DISTANCE_CLAMPED 0xD004
+#define AL_EXPONENT_DISTANCE 0xD005
+#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006
+
+/** Renderer State management. */
+AL_API void AL_APIENTRY alEnable(ALenum capability);
+AL_API void AL_APIENTRY alDisable(ALenum capability);
+AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability);
+
+/** State retrieval. */
+AL_API const ALchar* AL_APIENTRY alGetString(ALenum param);
+AL_API void AL_APIENTRY alGetBooleanv(ALenum param, ALboolean *values);
+AL_API void AL_APIENTRY alGetIntegerv(ALenum param, ALint *values);
+AL_API void AL_APIENTRY alGetFloatv(ALenum param, ALfloat *values);
+AL_API void AL_APIENTRY alGetDoublev(ALenum param, ALdouble *values);
+AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum param);
+AL_API ALint AL_APIENTRY alGetInteger(ALenum param);
+AL_API ALfloat AL_APIENTRY alGetFloat(ALenum param);
+AL_API ALdouble AL_APIENTRY alGetDouble(ALenum param);
+
+/**
+ * Error retrieval.
+ *
+ * Obtain the first error generated in the AL context since the last check.
+ */
+AL_API ALenum AL_APIENTRY alGetError(void);
+
+/**
+ * Extension support.
+ *
+ * Query for the presence of an extension, and obtain any appropriate function
+ * pointers and enum values.
+ */
+AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extname);
+AL_API void* AL_APIENTRY alGetProcAddress(const ALchar *fname);
+AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *ename);
+
+
+/** Set Listener parameters */
+AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value);
+AL_API void AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
+AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values);
+AL_API void AL_APIENTRY alListeneri(ALenum param, ALint value);
+AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3);
+AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values);
+
+/** Get Listener parameters */
+AL_API void AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value);
+AL_API void AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
+AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values);
+AL_API void AL_APIENTRY alGetListeneri(ALenum param, ALint *value);
+AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3);
+AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint *values);
+
+
+/** Create Source objects. */
+AL_API void AL_APIENTRY alGenSources(ALsizei n, ALuint *sources);
+/** Delete Source objects. */
+AL_API void AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources);
+/** Verify a handle is a valid Source. */
+AL_API ALboolean AL_APIENTRY alIsSource(ALuint source);
+
+/** Set Source parameters. */
+AL_API void AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value);
+AL_API void AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
+AL_API void AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values);
+AL_API void AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value);
+AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3);
+AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values);
+
+/** Get Source parameters. */
+AL_API void AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value);
+AL_API void AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
+AL_API void AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values);
+AL_API void AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value);
+AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3);
+AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values);
+
+
+/** Play, replay, or resume (if paused) a list of Sources */
+AL_API void AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources);
+/** Stop a list of Sources */
+AL_API void AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources);
+/** Rewind a list of Sources */
+AL_API void AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources);
+/** Pause a list of Sources */
+AL_API void AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources);
+
+/** Play, replay, or resume a Source */
+AL_API void AL_APIENTRY alSourcePlay(ALuint source);
+/** Stop a Source */
+AL_API void AL_APIENTRY alSourceStop(ALuint source);
+/** Rewind a Source (set playback postiton to beginning) */
+AL_API void AL_APIENTRY alSourceRewind(ALuint source);
+/** Pause a Source */
+AL_API void AL_APIENTRY alSourcePause(ALuint source);
+
+/** Queue buffers onto a source */
+AL_API void AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers);
+/** Unqueue processed buffers from a source */
+AL_API void AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers);
+
+
+/** Create Buffer objects */
+AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers);
+/** Delete Buffer objects */
+AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers);
+/** Verify a handle is a valid Buffer */
+AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer);
+
+/** Specifies the data to be copied into a buffer */
+AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq);
+
+/** Set Buffer parameters, */
+AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat value);
+AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
+AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values);
+AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value);
+AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3);
+AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values);
+
+/** Get Buffer parameters. */
+AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value);
+AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
+AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values);
+AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value);
+AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3);
+AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values);
+
+/** Pointer-to-function type, useful for dynamically getting AL entry points. */
+typedef void (AL_APIENTRY *LPALENABLE)(ALenum capability);
+typedef void (AL_APIENTRY *LPALDISABLE)(ALenum capability);
+typedef ALboolean (AL_APIENTRY *LPALISENABLED)(ALenum capability);
+typedef const ALchar* (AL_APIENTRY *LPALGETSTRING)(ALenum param);
+typedef void (AL_APIENTRY *LPALGETBOOLEANV)(ALenum param, ALboolean *values);
+typedef void (AL_APIENTRY *LPALGETINTEGERV)(ALenum param, ALint *values);
+typedef void (AL_APIENTRY *LPALGETFLOATV)(ALenum param, ALfloat *values);
+typedef void (AL_APIENTRY *LPALGETDOUBLEV)(ALenum param, ALdouble *values);
+typedef ALboolean (AL_APIENTRY *LPALGETBOOLEAN)(ALenum param);
+typedef ALint (AL_APIENTRY *LPALGETINTEGER)(ALenum param);
+typedef ALfloat (AL_APIENTRY *LPALGETFLOAT)(ALenum param);
+typedef ALdouble (AL_APIENTRY *LPALGETDOUBLE)(ALenum param);
+typedef ALenum (AL_APIENTRY *LPALGETERROR)(void);
+typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar *extname);
+typedef void* (AL_APIENTRY *LPALGETPROCADDRESS)(const ALchar *fname);
+typedef ALenum (AL_APIENTRY *LPALGETENUMVALUE)(const ALchar *ename);
+typedef void (AL_APIENTRY *LPALLISTENERF)(ALenum param, ALfloat value);
+typedef void (AL_APIENTRY *LPALLISTENER3F)(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
+typedef void (AL_APIENTRY *LPALLISTENERFV)(ALenum param, const ALfloat *values);
+typedef void (AL_APIENTRY *LPALLISTENERI)(ALenum param, ALint value);
+typedef void (AL_APIENTRY *LPALLISTENER3I)(ALenum param, ALint value1, ALint value2, ALint value3);
+typedef void (AL_APIENTRY *LPALLISTENERIV)(ALenum param, const ALint *values);
+typedef void (AL_APIENTRY *LPALGETLISTENERF)(ALenum param, ALfloat *value);
+typedef void (AL_APIENTRY *LPALGETLISTENER3F)(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
+typedef void (AL_APIENTRY *LPALGETLISTENERFV)(ALenum param, ALfloat *values);
+typedef void (AL_APIENTRY *LPALGETLISTENERI)(ALenum param, ALint *value);
+typedef void (AL_APIENTRY *LPALGETLISTENER3I)(ALenum param, ALint *value1, ALint *value2, ALint *value3);
+typedef void (AL_APIENTRY *LPALGETLISTENERIV)(ALenum param, ALint *values);
+typedef void (AL_APIENTRY *LPALGENSOURCES)(ALsizei n, ALuint *sources);
+typedef void (AL_APIENTRY *LPALDELETESOURCES)(ALsizei n, const ALuint *sources);
+typedef ALboolean (AL_APIENTRY *LPALISSOURCE)(ALuint source);
+typedef void (AL_APIENTRY *LPALSOURCEF)(ALuint source, ALenum param, ALfloat value);
+typedef void (AL_APIENTRY *LPALSOURCE3F)(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
+typedef void (AL_APIENTRY *LPALSOURCEFV)(ALuint source, ALenum param, const ALfloat *values);
+typedef void (AL_APIENTRY *LPALSOURCEI)(ALuint source, ALenum param, ALint value);
+typedef void (AL_APIENTRY *LPALSOURCE3I)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3);
+typedef void (AL_APIENTRY *LPALSOURCEIV)(ALuint source, ALenum param, const ALint *values);
+typedef void (AL_APIENTRY *LPALGETSOURCEF)(ALuint source, ALenum param, ALfloat *value);
+typedef void (AL_APIENTRY *LPALGETSOURCE3F)(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
+typedef void (AL_APIENTRY *LPALGETSOURCEFV)(ALuint source, ALenum param, ALfloat *values);
+typedef void (AL_APIENTRY *LPALGETSOURCEI)(ALuint source, ALenum param, ALint *value);
+typedef void (AL_APIENTRY *LPALGETSOURCE3I)(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3);
+typedef void (AL_APIENTRY *LPALGETSOURCEIV)(ALuint source, ALenum param, ALint *values);
+typedef void (AL_APIENTRY *LPALSOURCEPLAYV)(ALsizei n, const ALuint *sources);
+typedef void (AL_APIENTRY *LPALSOURCESTOPV)(ALsizei n, const ALuint *sources);
+typedef void (AL_APIENTRY *LPALSOURCEREWINDV)(ALsizei n, const ALuint *sources);
+typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)(ALsizei n, const ALuint *sources);
+typedef void (AL_APIENTRY *LPALSOURCEPLAY)(ALuint source);
+typedef void (AL_APIENTRY *LPALSOURCESTOP)(ALuint source);
+typedef void (AL_APIENTRY *LPALSOURCEREWIND)(ALuint source);
+typedef void (AL_APIENTRY *LPALSOURCEPAUSE)(ALuint source);
+typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint source, ALsizei nb, const ALuint *buffers);
+typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint source, ALsizei nb, ALuint *buffers);
+typedef void (AL_APIENTRY *LPALGENBUFFERS)(ALsizei n, ALuint *buffers);
+typedef void (AL_APIENTRY *LPALDELETEBUFFERS)(ALsizei n, const ALuint *buffers);
+typedef ALboolean (AL_APIENTRY *LPALISBUFFER)(ALuint buffer);
+typedef void (AL_APIENTRY *LPALBUFFERDATA)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq);
+typedef void (AL_APIENTRY *LPALBUFFERF)(ALuint buffer, ALenum param, ALfloat value);
+typedef void (AL_APIENTRY *LPALBUFFER3F)(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
+typedef void (AL_APIENTRY *LPALBUFFERFV)(ALuint buffer, ALenum param, const ALfloat *values);
+typedef void (AL_APIENTRY *LPALBUFFERI)(ALuint buffer, ALenum param, ALint value);
+typedef void (AL_APIENTRY *LPALBUFFER3I)(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3);
+typedef void (AL_APIENTRY *LPALBUFFERIV)(ALuint buffer, ALenum param, const ALint *values);
+typedef void (AL_APIENTRY *LPALGETBUFFERF)(ALuint buffer, ALenum param, ALfloat *value);
+typedef void (AL_APIENTRY *LPALGETBUFFER3F)(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
+typedef void (AL_APIENTRY *LPALGETBUFFERFV)(ALuint buffer, ALenum param, ALfloat *values);
+typedef void (AL_APIENTRY *LPALGETBUFFERI)(ALuint buffer, ALenum param, ALint *value);
+typedef void (AL_APIENTRY *LPALGETBUFFER3I)(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3);
+typedef void (AL_APIENTRY *LPALGETBUFFERIV)(ALuint buffer, ALenum param, ALint *values);
+typedef void (AL_APIENTRY *LPALDOPPLERFACTOR)(ALfloat value);
+typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)(ALfloat value);
+typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)(ALfloat value);
+typedef void (AL_APIENTRY *LPALDISTANCEMODEL)(ALenum distanceModel);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+#endif /* AL_AL_H */
diff --git a/src/external/openal_soft/include/AL/alc.h b/src/external/openal_soft/include/AL/alc.h
new file mode 100644
index 00000000..294e8b33
--- /dev/null
+++ b/src/external/openal_soft/include/AL/alc.h
@@ -0,0 +1,237 @@
+#ifndef AL_ALC_H
+#define AL_ALC_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef ALC_API
+ #if defined(AL_LIBTYPE_STATIC)
+ #define ALC_API
+ #elif defined(_WIN32)
+ #define ALC_API __declspec(dllimport)
+ #else
+ #define ALC_API extern
+ #endif
+#endif
+
+#if defined(_WIN32)
+ #define ALC_APIENTRY __cdecl
+#else
+ #define ALC_APIENTRY
+#endif
+
+
+/** Deprecated macro. */
+#define ALCAPI ALC_API
+#define ALCAPIENTRY ALC_APIENTRY
+#define ALC_INVALID 0
+
+/** Supported ALC version? */
+#define ALC_VERSION_0_1 1
+
+/** Opaque device handle */
+typedef struct ALCdevice_struct ALCdevice;
+/** Opaque context handle */
+typedef struct ALCcontext_struct ALCcontext;
+
+/** 8-bit boolean */
+typedef char ALCboolean;
+
+/** character */
+typedef char ALCchar;
+
+/** signed 8-bit 2's complement integer */
+typedef signed char ALCbyte;
+
+/** unsigned 8-bit integer */
+typedef unsigned char ALCubyte;
+
+/** signed 16-bit 2's complement integer */
+typedef short ALCshort;
+
+/** unsigned 16-bit integer */
+typedef unsigned short ALCushort;
+
+/** signed 32-bit 2's complement integer */
+typedef int ALCint;
+
+/** unsigned 32-bit integer */
+typedef unsigned int ALCuint;
+
+/** non-negative 32-bit binary integer size */
+typedef int ALCsizei;
+
+/** enumerated 32-bit value */
+typedef int ALCenum;
+
+/** 32-bit IEEE754 floating-point */
+typedef float ALCfloat;
+
+/** 64-bit IEEE754 floating-point */
+typedef double ALCdouble;
+
+/** void type (for opaque pointers only) */
+typedef void ALCvoid;
+
+
+/* Enumerant values begin at column 50. No tabs. */
+
+/** Boolean False. */
+#define ALC_FALSE 0
+
+/** Boolean True. */
+#define ALC_TRUE 1
+
+/** Context attribute: <int> Hz. */
+#define ALC_FREQUENCY 0x1007
+
+/** Context attribute: <int> Hz. */
+#define ALC_REFRESH 0x1008
+
+/** Context attribute: AL_TRUE or AL_FALSE. */
+#define ALC_SYNC 0x1009
+
+/** Context attribute: <int> requested Mono (3D) Sources. */
+#define ALC_MONO_SOURCES 0x1010
+
+/** Context attribute: <int> requested Stereo Sources. */
+#define ALC_STEREO_SOURCES 0x1011
+
+/** No error. */
+#define ALC_NO_ERROR 0
+
+/** Invalid device handle. */
+#define ALC_INVALID_DEVICE 0xA001
+
+/** Invalid context handle. */
+#define ALC_INVALID_CONTEXT 0xA002
+
+/** Invalid enum parameter passed to an ALC call. */
+#define ALC_INVALID_ENUM 0xA003
+
+/** Invalid value parameter passed to an ALC call. */
+#define ALC_INVALID_VALUE 0xA004
+
+/** Out of memory. */
+#define ALC_OUT_OF_MEMORY 0xA005
+
+
+/** Runtime ALC version. */
+#define ALC_MAJOR_VERSION 0x1000
+#define ALC_MINOR_VERSION 0x1001
+
+/** Context attribute list properties. */
+#define ALC_ATTRIBUTES_SIZE 0x1002
+#define ALC_ALL_ATTRIBUTES 0x1003
+
+/** String for the default device specifier. */
+#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004
+/**
+ * String for the given device's specifier.
+ *
+ * If device handle is NULL, it is instead a null-char separated list of
+ * strings of known device specifiers (list ends with an empty string).
+ */
+#define ALC_DEVICE_SPECIFIER 0x1005
+/** String for space-separated list of ALC extensions. */
+#define ALC_EXTENSIONS 0x1006
+
+
+/** Capture extension */
+#define ALC_EXT_CAPTURE 1
+/**
+ * String for the given capture device's specifier.
+ *
+ * If device handle is NULL, it is instead a null-char separated list of
+ * strings of known capture device specifiers (list ends with an empty string).
+ */
+#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310
+/** String for the default capture device specifier. */
+#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311
+/** Number of sample frames available for capture. */
+#define ALC_CAPTURE_SAMPLES 0x312
+
+
+/** Enumerate All extension */
+#define ALC_ENUMERATE_ALL_EXT 1
+/** String for the default extended device specifier. */
+#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012
+/**
+ * String for the given extended device's specifier.
+ *
+ * If device handle is NULL, it is instead a null-char separated list of
+ * strings of known extended device specifiers (list ends with an empty string).
+ */
+#define ALC_ALL_DEVICES_SPECIFIER 0x1013
+
+
+/** Context management. */
+ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint* attrlist);
+ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context);
+ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context);
+ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context);
+ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context);
+ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void);
+ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context);
+
+/** Device management. */
+ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename);
+ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device);
+
+
+/**
+ * Error support.
+ *
+ * Obtain the most recent Device error.
+ */
+ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device);
+
+/**
+ * Extension support.
+ *
+ * Query for the presence of an extension, and obtain any appropriate
+ * function pointers and enum values.
+ */
+ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname);
+ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname);
+ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname);
+
+/** Query function. */
+ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param);
+ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values);
+
+/** Capture function. */
+ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize);
+ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device);
+ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device);
+ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device);
+ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
+
+/** Pointer-to-function type, useful for dynamically getting ALC entry points. */
+typedef ALCcontext* (ALC_APIENTRY *LPALCCREATECONTEXT)(ALCdevice *device, const ALCint *attrlist);
+typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)(ALCcontext *context);
+typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)(ALCcontext *context);
+typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)(ALCcontext *context);
+typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)(ALCcontext *context);
+typedef ALCcontext* (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)(void);
+typedef ALCdevice* (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)(ALCcontext *context);
+typedef ALCdevice* (ALC_APIENTRY *LPALCOPENDEVICE)(const ALCchar *devicename);
+typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)(ALCdevice *device);
+typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)(ALCdevice *device);
+typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname);
+typedef void* (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname);
+typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname);
+typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)(ALCdevice *device, ALCenum param);
+typedef void (ALC_APIENTRY *LPALCGETINTEGERV)(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values);
+typedef ALCdevice* (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize);
+typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)(ALCdevice *device);
+typedef void (ALC_APIENTRY *LPALCCAPTURESTART)(ALCdevice *device);
+typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)(ALCdevice *device);
+typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* AL_ALC_H */
diff --git a/src/external/openal_soft/include/AL/alext.h b/src/external/openal_soft/include/AL/alext.h
new file mode 100644
index 00000000..0090c804
--- /dev/null
+++ b/src/external/openal_soft/include/AL/alext.h
@@ -0,0 +1,443 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2008 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef AL_ALEXT_H
+#define AL_ALEXT_H
+
+#include <stddef.h>
+/* Define int64_t and uint64_t types */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+#elif defined(_WIN32) && defined(__GNUC__)
+#include <stdint.h>
+#elif defined(_WIN32)
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+/* Fallback if nothing above works */
+#include <inttypes.h>
+#endif
+
+#include "alc.h"
+#include "al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef AL_LOKI_IMA_ADPCM_format
+#define AL_LOKI_IMA_ADPCM_format 1
+#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000
+#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001
+#endif
+
+#ifndef AL_LOKI_WAVE_format
+#define AL_LOKI_WAVE_format 1
+#define AL_FORMAT_WAVE_EXT 0x10002
+#endif
+
+#ifndef AL_EXT_vorbis
+#define AL_EXT_vorbis 1
+#define AL_FORMAT_VORBIS_EXT 0x10003
+#endif
+
+#ifndef AL_LOKI_quadriphonic
+#define AL_LOKI_quadriphonic 1
+#define AL_FORMAT_QUAD8_LOKI 0x10004
+#define AL_FORMAT_QUAD16_LOKI 0x10005
+#endif
+
+#ifndef AL_EXT_float32
+#define AL_EXT_float32 1
+#define AL_FORMAT_MONO_FLOAT32 0x10010
+#define AL_FORMAT_STEREO_FLOAT32 0x10011
+#endif
+
+#ifndef AL_EXT_double
+#define AL_EXT_double 1
+#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012
+#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013
+#endif
+
+#ifndef AL_EXT_MULAW
+#define AL_EXT_MULAW 1
+#define AL_FORMAT_MONO_MULAW_EXT 0x10014
+#define AL_FORMAT_STEREO_MULAW_EXT 0x10015
+#endif
+
+#ifndef AL_EXT_ALAW
+#define AL_EXT_ALAW 1
+#define AL_FORMAT_MONO_ALAW_EXT 0x10016
+#define AL_FORMAT_STEREO_ALAW_EXT 0x10017
+#endif
+
+#ifndef ALC_LOKI_audio_channel
+#define ALC_LOKI_audio_channel 1
+#define ALC_CHAN_MAIN_LOKI 0x500001
+#define ALC_CHAN_PCM_LOKI 0x500002
+#define ALC_CHAN_CD_LOKI 0x500003
+#endif
+
+#ifndef AL_EXT_MCFORMATS
+#define AL_EXT_MCFORMATS 1
+#define AL_FORMAT_QUAD8 0x1204
+#define AL_FORMAT_QUAD16 0x1205
+#define AL_FORMAT_QUAD32 0x1206
+#define AL_FORMAT_REAR8 0x1207
+#define AL_FORMAT_REAR16 0x1208
+#define AL_FORMAT_REAR32 0x1209
+#define AL_FORMAT_51CHN8 0x120A
+#define AL_FORMAT_51CHN16 0x120B
+#define AL_FORMAT_51CHN32 0x120C
+#define AL_FORMAT_61CHN8 0x120D
+#define AL_FORMAT_61CHN16 0x120E
+#define AL_FORMAT_61CHN32 0x120F
+#define AL_FORMAT_71CHN8 0x1210
+#define AL_FORMAT_71CHN16 0x1211
+#define AL_FORMAT_71CHN32 0x1212
+#endif
+
+#ifndef AL_EXT_MULAW_MCFORMATS
+#define AL_EXT_MULAW_MCFORMATS 1
+#define AL_FORMAT_MONO_MULAW 0x10014
+#define AL_FORMAT_STEREO_MULAW 0x10015
+#define AL_FORMAT_QUAD_MULAW 0x10021
+#define AL_FORMAT_REAR_MULAW 0x10022
+#define AL_FORMAT_51CHN_MULAW 0x10023
+#define AL_FORMAT_61CHN_MULAW 0x10024
+#define AL_FORMAT_71CHN_MULAW 0x10025
+#endif
+
+#ifndef AL_EXT_IMA4
+#define AL_EXT_IMA4 1
+#define AL_FORMAT_MONO_IMA4 0x1300
+#define AL_FORMAT_STEREO_IMA4 0x1301
+#endif
+
+#ifndef AL_EXT_STATIC_BUFFER
+#define AL_EXT_STATIC_BUFFER 1
+typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq);
+#endif
+#endif
+
+#ifndef ALC_EXT_EFX
+#define ALC_EXT_EFX 1
+#include "efx.h"
+#endif
+
+#ifndef ALC_EXT_disconnect
+#define ALC_EXT_disconnect 1
+#define ALC_CONNECTED 0x313
+#endif
+
+#ifndef ALC_EXT_thread_local_context
+#define ALC_EXT_thread_local_context 1
+typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context);
+typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void);
+#ifdef AL_ALEXT_PROTOTYPES
+ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context);
+ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void);
+#endif
+#endif
+
+#ifndef AL_EXT_source_distance_model
+#define AL_EXT_source_distance_model 1
+#define AL_SOURCE_DISTANCE_MODEL 0x200
+#endif
+
+#ifndef AL_SOFT_buffer_sub_data
+#define AL_SOFT_buffer_sub_data 1
+#define AL_BYTE_RW_OFFSETS_SOFT 0x1031
+#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032
+typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length);
+#endif
+#endif
+
+#ifndef AL_SOFT_loop_points
+#define AL_SOFT_loop_points 1
+#define AL_LOOP_POINTS_SOFT 0x2015
+#endif
+
+#ifndef AL_EXT_FOLDBACK
+#define AL_EXT_FOLDBACK 1
+#define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK"
+#define AL_FOLDBACK_EVENT_BLOCK 0x4112
+#define AL_FOLDBACK_EVENT_START 0x4111
+#define AL_FOLDBACK_EVENT_STOP 0x4113
+#define AL_FOLDBACK_MODE_MONO 0x4101
+#define AL_FOLDBACK_MODE_STEREO 0x4102
+typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei);
+typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK);
+typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback);
+AL_API void AL_APIENTRY alRequestFoldbackStop(void);
+#endif
+#endif
+
+#ifndef ALC_EXT_DEDICATED
+#define ALC_EXT_DEDICATED 1
+#define AL_DEDICATED_GAIN 0x0001
+#define AL_EFFECT_DEDICATED_DIALOGUE 0x9001
+#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000
+#endif
+
+#ifndef AL_SOFT_buffer_samples
+#define AL_SOFT_buffer_samples 1
+/* Channel configurations */
+#define AL_MONO_SOFT 0x1500
+#define AL_STEREO_SOFT 0x1501
+#define AL_REAR_SOFT 0x1502
+#define AL_QUAD_SOFT 0x1503
+#define AL_5POINT1_SOFT 0x1504
+#define AL_6POINT1_SOFT 0x1505
+#define AL_7POINT1_SOFT 0x1506
+
+/* Sample types */
+#define AL_BYTE_SOFT 0x1400
+#define AL_UNSIGNED_BYTE_SOFT 0x1401
+#define AL_SHORT_SOFT 0x1402
+#define AL_UNSIGNED_SHORT_SOFT 0x1403
+#define AL_INT_SOFT 0x1404
+#define AL_UNSIGNED_INT_SOFT 0x1405
+#define AL_FLOAT_SOFT 0x1406
+#define AL_DOUBLE_SOFT 0x1407
+#define AL_BYTE3_SOFT 0x1408
+#define AL_UNSIGNED_BYTE3_SOFT 0x1409
+
+/* Storage formats */
+#define AL_MONO8_SOFT 0x1100
+#define AL_MONO16_SOFT 0x1101
+#define AL_MONO32F_SOFT 0x10010
+#define AL_STEREO8_SOFT 0x1102
+#define AL_STEREO16_SOFT 0x1103
+#define AL_STEREO32F_SOFT 0x10011
+#define AL_QUAD8_SOFT 0x1204
+#define AL_QUAD16_SOFT 0x1205
+#define AL_QUAD32F_SOFT 0x1206
+#define AL_REAR8_SOFT 0x1207
+#define AL_REAR16_SOFT 0x1208
+#define AL_REAR32F_SOFT 0x1209
+#define AL_5POINT1_8_SOFT 0x120A
+#define AL_5POINT1_16_SOFT 0x120B
+#define AL_5POINT1_32F_SOFT 0x120C
+#define AL_6POINT1_8_SOFT 0x120D
+#define AL_6POINT1_16_SOFT 0x120E
+#define AL_6POINT1_32F_SOFT 0x120F
+#define AL_7POINT1_8_SOFT 0x1210
+#define AL_7POINT1_16_SOFT 0x1211
+#define AL_7POINT1_32F_SOFT 0x1212
+
+/* Buffer attributes */
+#define AL_INTERNAL_FORMAT_SOFT 0x2008
+#define AL_BYTE_LENGTH_SOFT 0x2009
+#define AL_SAMPLE_LENGTH_SOFT 0x200A
+#define AL_SEC_LENGTH_SOFT 0x200B
+
+typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*);
+typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*);
+typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*);
+typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data);
+AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data);
+AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data);
+AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format);
+#endif
+#endif
+
+#ifndef AL_SOFT_direct_channels
+#define AL_SOFT_direct_channels 1
+#define AL_DIRECT_CHANNELS_SOFT 0x1033
+#endif
+
+#ifndef ALC_SOFT_loopback
+#define ALC_SOFT_loopback 1
+#define ALC_FORMAT_CHANNELS_SOFT 0x1990
+#define ALC_FORMAT_TYPE_SOFT 0x1991
+
+/* Sample types */
+#define ALC_BYTE_SOFT 0x1400
+#define ALC_UNSIGNED_BYTE_SOFT 0x1401
+#define ALC_SHORT_SOFT 0x1402
+#define ALC_UNSIGNED_SHORT_SOFT 0x1403
+#define ALC_INT_SOFT 0x1404
+#define ALC_UNSIGNED_INT_SOFT 0x1405
+#define ALC_FLOAT_SOFT 0x1406
+
+/* Channel configurations */
+#define ALC_MONO_SOFT 0x1500
+#define ALC_STEREO_SOFT 0x1501
+#define ALC_QUAD_SOFT 0x1503
+#define ALC_5POINT1_SOFT 0x1504
+#define ALC_6POINT1_SOFT 0x1505
+#define ALC_7POINT1_SOFT 0x1506
+
+typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*);
+typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum);
+typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei);
+#ifdef AL_ALEXT_PROTOTYPES
+ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName);
+ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type);
+ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
+#endif
+#endif
+
+#ifndef AL_EXT_STEREO_ANGLES
+#define AL_EXT_STEREO_ANGLES 1
+#define AL_STEREO_ANGLES 0x1030
+#endif
+
+#ifndef AL_EXT_SOURCE_RADIUS
+#define AL_EXT_SOURCE_RADIUS 1
+#define AL_SOURCE_RADIUS 0x1031
+#endif
+
+#ifndef AL_SOFT_source_latency
+#define AL_SOFT_source_latency 1
+#define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200
+#define AL_SEC_OFFSET_LATENCY_SOFT 0x1201
+typedef int64_t ALint64SOFT;
+typedef uint64_t ALuint64SOFT;
+typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble);
+typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble);
+typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*);
+typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*);
+typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*);
+typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*);
+typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT);
+typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT);
+typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*);
+typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*);
+typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*);
+typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value);
+AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3);
+AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values);
+AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value);
+AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3);
+AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values);
+AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value);
+AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3);
+AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values);
+AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value);
+AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3);
+AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values);
+#endif
+#endif
+
+#ifndef ALC_EXT_DEFAULT_FILTER_ORDER
+#define ALC_EXT_DEFAULT_FILTER_ORDER 1
+#define ALC_DEFAULT_FILTER_ORDER 0x1100
+#endif
+
+#ifndef AL_SOFT_deferred_updates
+#define AL_SOFT_deferred_updates 1
+#define AL_DEFERRED_UPDATES_SOFT 0xC002
+typedef ALvoid (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void);
+typedef ALvoid (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void);
+AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void);
+#endif
+#endif
+
+#ifndef AL_SOFT_block_alignment
+#define AL_SOFT_block_alignment 1
+#define AL_UNPACK_BLOCK_ALIGNMENT_SOFT 0x200C
+#define AL_PACK_BLOCK_ALIGNMENT_SOFT 0x200D
+#endif
+
+#ifndef AL_SOFT_MSADPCM
+#define AL_SOFT_MSADPCM 1
+#define AL_FORMAT_MONO_MSADPCM_SOFT 0x1302
+#define AL_FORMAT_STEREO_MSADPCM_SOFT 0x1303
+#endif
+
+#ifndef AL_SOFT_source_length
+#define AL_SOFT_source_length 1
+/*#define AL_BYTE_LENGTH_SOFT 0x2009*/
+/*#define AL_SAMPLE_LENGTH_SOFT 0x200A*/
+/*#define AL_SEC_LENGTH_SOFT 0x200B*/
+#endif
+
+#ifndef ALC_SOFT_pause_device
+#define ALC_SOFT_pause_device 1
+typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device);
+typedef void (ALC_APIENTRY*LPALCDEVICERESUMESOFT)(ALCdevice *device);
+#ifdef AL_ALEXT_PROTOTYPES
+ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device);
+ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device);
+#endif
+#endif
+
+#ifndef AL_EXT_BFORMAT
+#define AL_EXT_BFORMAT 1
+#define AL_FORMAT_BFORMAT2D_8 0x20021
+#define AL_FORMAT_BFORMAT2D_16 0x20022
+#define AL_FORMAT_BFORMAT2D_FLOAT32 0x20023
+#define AL_FORMAT_BFORMAT3D_8 0x20031
+#define AL_FORMAT_BFORMAT3D_16 0x20032
+#define AL_FORMAT_BFORMAT3D_FLOAT32 0x20033
+#endif
+
+#ifndef AL_EXT_MULAW_BFORMAT
+#define AL_EXT_MULAW_BFORMAT 1
+#define AL_FORMAT_BFORMAT2D_MULAW 0x10031
+#define AL_FORMAT_BFORMAT3D_MULAW 0x10032
+#endif
+
+#ifndef ALC_SOFT_HRTF
+#define ALC_SOFT_HRTF 1
+#define ALC_HRTF_SOFT 0x1992
+#define ALC_DONT_CARE_SOFT 0x0002
+#define ALC_HRTF_STATUS_SOFT 0x1993
+#define ALC_HRTF_DISABLED_SOFT 0x0000
+#define ALC_HRTF_ENABLED_SOFT 0x0001
+#define ALC_HRTF_DENIED_SOFT 0x0002
+#define ALC_HRTF_REQUIRED_SOFT 0x0003
+#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004
+#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005
+#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994
+#define ALC_HRTF_SPECIFIER_SOFT 0x1995
+#define ALC_HRTF_ID_SOFT 0x1996
+typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index);
+typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs);
+#ifdef AL_ALEXT_PROTOTYPES
+ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index);
+ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs);
+#endif
+#endif
+
+#ifndef AL_SOFT_gain_clamp_ex
+#define AL_SOFT_gain_clamp_ex 1
+#define AL_GAIN_LIMIT_SOFT 0x200E
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/external/openal_soft/include/AL/efx-creative.h b/src/external/openal_soft/include/AL/efx-creative.h
new file mode 100644
index 00000000..0a04c982
--- /dev/null
+++ b/src/external/openal_soft/include/AL/efx-creative.h
@@ -0,0 +1,3 @@
+/* The tokens that would be defined here are already defined in efx.h. This
+ * empty file is here to provide compatibility with Windows-based projects
+ * that would include it. */
diff --git a/src/external/openal_soft/include/AL/efx-presets.h b/src/external/openal_soft/include/AL/efx-presets.h
new file mode 100644
index 00000000..8539fd51
--- /dev/null
+++ b/src/external/openal_soft/include/AL/efx-presets.h
@@ -0,0 +1,402 @@
+/* Reverb presets for EFX */
+
+#ifndef EFX_PRESETS_H
+#define EFX_PRESETS_H
+
+#ifndef EFXEAXREVERBPROPERTIES_DEFINED
+#define EFXEAXREVERBPROPERTIES_DEFINED
+typedef struct {
+ float flDensity;
+ float flDiffusion;
+ float flGain;
+ float flGainHF;
+ float flGainLF;
+ float flDecayTime;
+ float flDecayHFRatio;
+ float flDecayLFRatio;
+ float flReflectionsGain;
+ float flReflectionsDelay;
+ float flReflectionsPan[3];
+ float flLateReverbGain;
+ float flLateReverbDelay;
+ float flLateReverbPan[3];
+ float flEchoTime;
+ float flEchoDepth;
+ float flModulationTime;
+ float flModulationDepth;
+ float flAirAbsorptionGainHF;
+ float flHFReference;
+ float flLFReference;
+ float flRoomRolloffFactor;
+ int iDecayHFLimit;
+} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES;
+#endif
+
+/* Default Presets */
+
+#define EFX_REVERB_PRESET_GENERIC \
+ { 1.0000f, 1.0000f, 0.3162f, 0.8913f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PADDEDCELL \
+ { 0.1715f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.1700f, 0.1000f, 1.0000f, 0.2500f, 0.0010f, { 0.0000f, 0.0000f, 0.0000f }, 1.2691f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ROOM \
+ { 0.4287f, 1.0000f, 0.3162f, 0.5929f, 1.0000f, 0.4000f, 0.8300f, 1.0000f, 0.1503f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.0629f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_BATHROOM \
+ { 0.1715f, 1.0000f, 0.3162f, 0.2512f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.6531f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 3.2734f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_LIVINGROOM \
+ { 0.9766f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.5000f, 0.1000f, 1.0000f, 0.2051f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2805f, 0.0040f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_STONEROOM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 2.3100f, 0.6400f, 1.0000f, 0.4411f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1003f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_AUDITORIUM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.5781f, 1.0000f, 4.3200f, 0.5900f, 1.0000f, 0.4032f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7170f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CONCERTHALL \
+ { 1.0000f, 1.0000f, 0.3162f, 0.5623f, 1.0000f, 3.9200f, 0.7000f, 1.0000f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.9977f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CAVE \
+ { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 2.9100f, 1.3000f, 1.0000f, 0.5000f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.7063f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_ARENA \
+ { 1.0000f, 1.0000f, 0.3162f, 0.4477f, 1.0000f, 7.2400f, 0.3300f, 1.0000f, 0.2612f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.0186f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_HANGAR \
+ { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 10.0500f, 0.2300f, 1.0000f, 0.5000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2560f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CARPETEDHALLWAY \
+ { 0.4287f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 0.3000f, 0.1000f, 1.0000f, 0.1215f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.1531f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_HALLWAY \
+ { 0.3645f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 1.4900f, 0.5900f, 1.0000f, 0.2458f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.6615f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_STONECORRIDOR \
+ { 1.0000f, 1.0000f, 0.3162f, 0.7612f, 1.0000f, 2.7000f, 0.7900f, 1.0000f, 0.2472f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 1.5758f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ALLEY \
+ { 1.0000f, 0.3000f, 0.3162f, 0.7328f, 1.0000f, 1.4900f, 0.8600f, 1.0000f, 0.2500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.9954f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.9500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FOREST \
+ { 1.0000f, 0.3000f, 0.3162f, 0.0224f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.0525f, 0.1620f, { 0.0000f, 0.0000f, 0.0000f }, 0.7682f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CITY \
+ { 1.0000f, 0.5000f, 0.3162f, 0.3981f, 1.0000f, 1.4900f, 0.6700f, 1.0000f, 0.0730f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1427f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_MOUNTAINS \
+ { 1.0000f, 0.2700f, 0.3162f, 0.0562f, 1.0000f, 1.4900f, 0.2100f, 1.0000f, 0.0407f, 0.3000f, { 0.0000f, 0.0000f, 0.0000f }, 0.1919f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_QUARRY \
+ { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0000f, 0.0610f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.7000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PLAIN \
+ { 1.0000f, 0.2100f, 0.3162f, 0.1000f, 1.0000f, 1.4900f, 0.5000f, 1.0000f, 0.0585f, 0.1790f, { 0.0000f, 0.0000f, 0.0000f }, 0.1089f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PARKINGLOT \
+ { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 1.6500f, 1.5000f, 1.0000f, 0.2082f, 0.0080f, { 0.0000f, 0.0000f, 0.0000f }, 0.2652f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_SEWERPIPE \
+ { 0.3071f, 0.8000f, 0.3162f, 0.3162f, 1.0000f, 2.8100f, 0.1400f, 1.0000f, 1.6387f, 0.0140f, { 0.0000f, 0.0000f, 0.0000f }, 3.2471f, 0.0210f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_UNDERWATER \
+ { 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_DRUGGED \
+ { 0.4287f, 0.5000f, 0.3162f, 1.0000f, 1.0000f, 8.3900f, 1.3900f, 1.0000f, 0.8760f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 3.1081f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_DIZZY \
+ { 0.3645f, 0.6000f, 0.3162f, 0.6310f, 1.0000f, 17.2300f, 0.5600f, 1.0000f, 0.1392f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4937f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.8100f, 0.3100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_PSYCHOTIC \
+ { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+/* Castle Presets */
+
+#define EFX_REVERB_PRESET_CASTLE_SMALLROOM \
+ { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 1.2200f, 0.8300f, 0.3100f, 0.8913f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE \
+ { 1.0000f, 0.8900f, 0.3162f, 0.3162f, 0.1000f, 2.3200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_MEDIUMROOM \
+ { 1.0000f, 0.9300f, 0.3162f, 0.2818f, 0.1000f, 2.0400f, 0.8300f, 0.4600f, 0.6310f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1550f, 0.0300f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_LARGEROOM \
+ { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.1259f, 2.5300f, 0.8300f, 0.5000f, 0.4467f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1850f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_LONGPASSAGE \
+ { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 3.4200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_HALL \
+ { 1.0000f, 0.8100f, 0.3162f, 0.2818f, 0.1778f, 3.1400f, 0.7900f, 0.6200f, 0.1778f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_CUPBOARD \
+ { 1.0000f, 0.8900f, 0.3162f, 0.2818f, 0.1000f, 0.6700f, 0.8700f, 0.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 3.5481f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CASTLE_COURTYARD \
+ { 1.0000f, 0.4200f, 0.3162f, 0.4467f, 0.1995f, 2.1300f, 0.6100f, 0.2300f, 0.2239f, 0.1600f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3700f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_CASTLE_ALCOVE \
+ { 1.0000f, 0.8900f, 0.3162f, 0.5012f, 0.1000f, 1.6400f, 0.8700f, 0.3100f, 1.0000f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
+
+/* Factory Presets */
+
+#define EFX_REVERB_PRESET_FACTORY_SMALLROOM \
+ { 0.3645f, 0.8200f, 0.3162f, 0.7943f, 0.5012f, 1.7200f, 0.6500f, 1.3100f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.1190f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE \
+ { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 2.5300f, 0.6500f, 1.3100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_MEDIUMROOM \
+ { 0.4287f, 0.8200f, 0.2512f, 0.7943f, 0.5012f, 2.7600f, 0.6500f, 1.3100f, 0.2818f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1740f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_LARGEROOM \
+ { 0.4287f, 0.7500f, 0.2512f, 0.7079f, 0.6310f, 4.2400f, 0.5100f, 1.3100f, 0.1778f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2310f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_LONGPASSAGE \
+ { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 4.0600f, 0.6500f, 1.3100f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_HALL \
+ { 0.4287f, 0.7500f, 0.3162f, 0.7079f, 0.6310f, 7.4300f, 0.5100f, 1.3100f, 0.0631f, 0.0730f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_CUPBOARD \
+ { 0.3071f, 0.6300f, 0.2512f, 0.7943f, 0.5012f, 0.4900f, 0.6500f, 1.3100f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.1070f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_COURTYARD \
+ { 0.3071f, 0.5700f, 0.3162f, 0.3162f, 0.6310f, 2.3200f, 0.2900f, 0.5600f, 0.2239f, 0.1400f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2900f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_FACTORY_ALCOVE \
+ { 0.3645f, 0.5900f, 0.2512f, 0.7943f, 0.5012f, 3.1400f, 0.6500f, 1.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1140f, 0.1000f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
+
+/* Ice Palace Presets */
+
+#define EFX_REVERB_PRESET_ICEPALACE_SMALLROOM \
+ { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 1.5100f, 1.5300f, 0.2700f, 0.8913f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1640f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_SHORTPASSAGE \
+ { 1.0000f, 0.7500f, 0.3162f, 0.5623f, 0.2818f, 1.7900f, 1.4600f, 0.2800f, 0.5012f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_MEDIUMROOM \
+ { 1.0000f, 0.8700f, 0.3162f, 0.5623f, 0.4467f, 2.2200f, 1.5300f, 0.3200f, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_LARGEROOM \
+ { 1.0000f, 0.8100f, 0.3162f, 0.5623f, 0.4467f, 3.1400f, 1.5300f, 0.3200f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_LONGPASSAGE \
+ { 1.0000f, 0.7700f, 0.3162f, 0.5623f, 0.3981f, 3.0100f, 1.4600f, 0.2800f, 0.7943f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.0400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_HALL \
+ { 1.0000f, 0.7600f, 0.3162f, 0.4467f, 0.5623f, 5.4900f, 1.5300f, 0.3800f, 0.1122f, 0.0540f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0520f, { 0.0000f, 0.0000f, 0.0000f }, 0.2260f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_CUPBOARD \
+ { 1.0000f, 0.8300f, 0.3162f, 0.5012f, 0.2239f, 0.7600f, 1.5300f, 0.2600f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1430f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_COURTYARD \
+ { 1.0000f, 0.5900f, 0.3162f, 0.2818f, 0.3162f, 2.0400f, 1.2000f, 0.3800f, 0.3162f, 0.1730f, { 0.0000f, 0.0000f, 0.0000f }, 0.3162f, 0.0430f, { 0.0000f, 0.0000f, 0.0000f }, 0.2350f, 0.4800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_ICEPALACE_ALCOVE \
+ { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 2.7600f, 1.4600f, 0.2800f, 1.1220f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1610f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
+
+/* Space Station Presets */
+
+#define EFX_REVERB_PRESET_SPACESTATION_SMALLROOM \
+ { 0.2109f, 0.7000f, 0.3162f, 0.7079f, 0.8913f, 1.7200f, 0.8200f, 0.5500f, 0.7943f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 0.1880f, 0.2600f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE \
+ { 0.2109f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 3.5700f, 0.5000f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1720f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM \
+ { 0.2109f, 0.7500f, 0.3162f, 0.6310f, 0.8913f, 3.0100f, 0.5000f, 0.5500f, 0.3981f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2090f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_LARGEROOM \
+ { 0.3645f, 0.8100f, 0.3162f, 0.6310f, 0.8913f, 3.8900f, 0.3800f, 0.6100f, 0.3162f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2330f, 0.2800f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE \
+ { 0.4287f, 0.8200f, 0.3162f, 0.6310f, 0.8913f, 4.6200f, 0.6200f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_HALL \
+ { 0.4287f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 7.1100f, 0.3800f, 0.6100f, 0.1778f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2500f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_CUPBOARD \
+ { 0.1715f, 0.5600f, 0.3162f, 0.7079f, 0.8913f, 0.7900f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1810f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPACESTATION_ALCOVE \
+ { 0.2109f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.1600f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1920f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
+
+/* Wooden Galleon Presets */
+
+#define EFX_REVERB_PRESET_WOODEN_SMALLROOM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.1122f, 0.3162f, 0.7900f, 0.3200f, 0.8700f, 1.0000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE \
+ { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.7500f, 0.5000f, 0.8700f, 0.8913f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_MEDIUMROOM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.2818f, 1.4700f, 0.4200f, 0.8200f, 0.8913f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_LARGEROOM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.2818f, 2.6500f, 0.3300f, 0.8200f, 0.8913f, 0.0660f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_LONGPASSAGE \
+ { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.3162f, 1.9900f, 0.4000f, 0.7900f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4467f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_HALL \
+ { 1.0000f, 1.0000f, 0.3162f, 0.0794f, 0.2818f, 3.4500f, 0.3000f, 0.8200f, 0.8913f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_CUPBOARD \
+ { 1.0000f, 1.0000f, 0.3162f, 0.1413f, 0.3162f, 0.5600f, 0.4600f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_COURTYARD \
+ { 1.0000f, 0.6500f, 0.3162f, 0.0794f, 0.3162f, 1.7900f, 0.3500f, 0.7900f, 0.5623f, 0.1230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_WOODEN_ALCOVE \
+ { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.2200f, 0.6200f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
+
+/* Sports Presets */
+
+#define EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.4467f, 0.7943f, 6.2600f, 0.5100f, 1.1000f, 0.0631f, 0.1830f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPORT_SQUASHCOURT \
+ { 1.0000f, 0.7500f, 0.3162f, 0.3162f, 0.7943f, 2.2200f, 0.9100f, 1.1600f, 0.4467f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1260f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPORT_SMALLSWIMMINGPOOL \
+ { 1.0000f, 0.7000f, 0.3162f, 0.7943f, 0.8913f, 2.7600f, 1.2500f, 1.1400f, 0.6310f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_SPORT_LARGESWIMMINGPOOL \
+ { 1.0000f, 0.8200f, 0.3162f, 0.7943f, 1.0000f, 5.4900f, 1.3100f, 1.1400f, 0.4467f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2220f, 0.5500f, 1.1590f, 0.2100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_SPORT_GYMNASIUM \
+ { 1.0000f, 0.8100f, 0.3162f, 0.4467f, 0.8913f, 3.1400f, 1.0600f, 1.3500f, 0.3981f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0450f, { 0.0000f, 0.0000f, 0.0000f }, 0.1460f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPORT_FULLSTADIUM \
+ { 1.0000f, 1.0000f, 0.3162f, 0.0708f, 0.7943f, 5.2500f, 0.1700f, 0.8000f, 0.1000f, 0.1880f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SPORT_STADIUMTANNOY \
+ { 1.0000f, 0.7800f, 0.3162f, 0.5623f, 0.5012f, 2.5300f, 0.8800f, 0.6800f, 0.2818f, 0.2300f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+/* Prefab Presets */
+
+#define EFX_REVERB_PRESET_PREFAB_WORKSHOP \
+ { 0.4287f, 1.0000f, 0.3162f, 0.1413f, 0.3981f, 0.7600f, 1.0000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_PREFAB_SCHOOLROOM \
+ { 0.4022f, 0.6900f, 0.3162f, 0.6310f, 0.5012f, 0.9800f, 0.4500f, 0.1800f, 1.4125f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PREFAB_PRACTISEROOM \
+ { 0.4022f, 0.8700f, 0.3162f, 0.3981f, 0.5012f, 1.1200f, 0.5600f, 0.1800f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PREFAB_OUTHOUSE \
+ { 1.0000f, 0.8200f, 0.3162f, 0.1122f, 0.1585f, 1.3800f, 0.3800f, 0.3500f, 0.8913f, 0.0240f, { 0.0000f, 0.0000f, -0.0000f }, 0.6310f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.1210f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_PREFAB_CARAVAN \
+ { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.1259f, 0.4300f, 1.5000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+/* Dome and Pipe Presets */
+
+#define EFX_REVERB_PRESET_DOME_TOMB \
+ { 1.0000f, 0.7900f, 0.3162f, 0.3548f, 0.2239f, 4.1800f, 0.2100f, 0.1000f, 0.3868f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 1.6788f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_PIPE_SMALL \
+ { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 5.0400f, 0.1000f, 0.1000f, 0.5012f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 2.5119f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_DOME_SAINTPAULS \
+ { 1.0000f, 0.8700f, 0.3162f, 0.3548f, 0.2239f, 10.4800f, 0.1900f, 0.1000f, 0.1778f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0420f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PIPE_LONGTHIN \
+ { 0.2560f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 9.2100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_PIPE_LARGE \
+ { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 8.4500f, 0.1000f, 0.1000f, 0.3981f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_PIPE_RESONANT \
+ { 0.1373f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 6.8100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 }
+
+/* Outdoors Presets */
+
+#define EFX_REVERB_PRESET_OUTDOORS_BACKYARD \
+ { 1.0000f, 0.4500f, 0.3162f, 0.2512f, 0.5012f, 1.1200f, 0.3400f, 0.4600f, 0.4467f, 0.0690f, { 0.0000f, 0.0000f, -0.0000f }, 0.7079f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS \
+ { 1.0000f, 0.0000f, 0.3162f, 0.0112f, 0.6310f, 2.1300f, 0.2100f, 0.4600f, 0.1778f, 0.3000f, { 0.0000f, 0.0000f, -0.0000f }, 0.4467f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON \
+ { 1.0000f, 0.7400f, 0.3162f, 0.1778f, 0.6310f, 3.8900f, 0.2100f, 0.4600f, 0.3162f, 0.2230f, { 0.0000f, 0.0000f, -0.0000f }, 0.3548f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_OUTDOORS_CREEK \
+ { 1.0000f, 0.3500f, 0.3162f, 0.1778f, 0.5012f, 2.1300f, 0.2100f, 0.4600f, 0.3981f, 0.1150f, { 0.0000f, 0.0000f, -0.0000f }, 0.1995f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_OUTDOORS_VALLEY \
+ { 1.0000f, 0.2800f, 0.3162f, 0.0282f, 0.1585f, 2.8800f, 0.2600f, 0.3500f, 0.1413f, 0.2630f, { 0.0000f, 0.0000f, -0.0000f }, 0.3981f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
+
+/* Mood Presets */
+
+#define EFX_REVERB_PRESET_MOOD_HEAVEN \
+ { 1.0000f, 0.9400f, 0.3162f, 0.7943f, 0.4467f, 5.0400f, 1.1200f, 0.5600f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0800f, 2.7420f, 0.0500f, 0.9977f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_MOOD_HELL \
+ { 1.0000f, 0.5700f, 0.3162f, 0.3548f, 0.4467f, 3.5700f, 0.4900f, 2.0000f, 0.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1100f, 0.0400f, 2.1090f, 0.5200f, 0.9943f, 5000.0000f, 139.5000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_MOOD_MEMORY \
+ { 1.0000f, 0.8500f, 0.3162f, 0.6310f, 0.3548f, 4.0600f, 0.8200f, 0.5600f, 0.0398f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.4740f, 0.4500f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+/* Driving Presets */
+
+#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \
+ { 1.0000f, 0.0000f, 0.3162f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \
+ { 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_DRIVING_INCAR_RACER \
+ { 0.0832f, 0.8000f, 0.3162f, 1.0000f, 0.7943f, 0.1700f, 2.0000f, 0.4100f, 1.7783f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS \
+ { 0.0832f, 0.8000f, 0.3162f, 0.6310f, 1.0000f, 0.1700f, 0.7500f, 0.4100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY \
+ { 0.2560f, 1.0000f, 0.3162f, 0.1000f, 0.5012f, 0.1300f, 0.4100f, 0.4600f, 0.7943f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND \
+ { 1.0000f, 1.0000f, 0.3162f, 0.2818f, 0.6310f, 3.0100f, 1.3700f, 1.2800f, 0.3548f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.1778f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND \
+ { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 0.7943f, 4.6200f, 1.7500f, 1.4000f, 0.2082f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_DRIVING_TUNNEL \
+ { 1.0000f, 0.8100f, 0.3162f, 0.3981f, 0.8913f, 3.4200f, 0.9400f, 1.3100f, 0.7079f, 0.0510f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.0500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 155.3000f, 0.0000f, 0x1 }
+
+/* City Presets */
+
+#define EFX_REVERB_PRESET_CITY_STREETS \
+ { 1.0000f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.7900f, 1.1200f, 0.9100f, 0.2818f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 0.1995f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CITY_SUBWAY \
+ { 1.0000f, 0.7400f, 0.3162f, 0.7079f, 0.8913f, 3.0100f, 1.2300f, 0.9100f, 0.7079f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CITY_MUSEUM \
+ { 1.0000f, 0.8200f, 0.3162f, 0.1778f, 0.1778f, 3.2800f, 1.4000f, 0.5700f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_CITY_LIBRARY \
+ { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.0891f, 2.7600f, 0.8900f, 0.4100f, 0.3548f, 0.0290f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
+
+#define EFX_REVERB_PRESET_CITY_UNDERPASS \
+ { 1.0000f, 0.8200f, 0.3162f, 0.4467f, 0.8913f, 3.5700f, 1.1200f, 0.9100f, 0.3981f, 0.0590f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1400f, 0.2500f, 0.0000f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CITY_ABANDONED \
+ { 1.0000f, 0.6900f, 0.3162f, 0.7943f, 0.8913f, 3.2800f, 1.1700f, 0.9100f, 0.4467f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9966f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+/* Misc. Presets */
+
+#define EFX_REVERB_PRESET_DUSTYROOM \
+ { 0.3645f, 0.5600f, 0.3162f, 0.7943f, 0.7079f, 1.7900f, 0.3800f, 0.2100f, 0.5012f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0060f, { 0.0000f, 0.0000f, 0.0000f }, 0.2020f, 0.0500f, 0.2500f, 0.0000f, 0.9886f, 13046.0000f, 163.3000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_CHAPEL \
+ { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 1.0000f, 4.6200f, 0.6400f, 1.2300f, 0.4467f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.1100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+
+#define EFX_REVERB_PRESET_SMALLWATERROOM \
+ { 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+
+#endif /* EFX_PRESETS_H */
diff --git a/src/external/openal_soft/include/AL/efx.h b/src/external/openal_soft/include/AL/efx.h
new file mode 100644
index 00000000..57766983
--- /dev/null
+++ b/src/external/openal_soft/include/AL/efx.h
@@ -0,0 +1,761 @@
+#ifndef AL_EFX_H
+#define AL_EFX_H
+
+
+#include "alc.h"
+#include "al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ALC_EXT_EFX_NAME "ALC_EXT_EFX"
+
+#define ALC_EFX_MAJOR_VERSION 0x20001
+#define ALC_EFX_MINOR_VERSION 0x20002
+#define ALC_MAX_AUXILIARY_SENDS 0x20003
+
+
+/* Listener properties. */
+#define AL_METERS_PER_UNIT 0x20004
+
+/* Source properties. */
+#define AL_DIRECT_FILTER 0x20005
+#define AL_AUXILIARY_SEND_FILTER 0x20006
+#define AL_AIR_ABSORPTION_FACTOR 0x20007
+#define AL_ROOM_ROLLOFF_FACTOR 0x20008
+#define AL_CONE_OUTER_GAINHF 0x20009
+#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A
+#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B
+#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C
+
+
+/* Effect properties. */
+
+/* Reverb effect parameters */
+#define AL_REVERB_DENSITY 0x0001
+#define AL_REVERB_DIFFUSION 0x0002
+#define AL_REVERB_GAIN 0x0003
+#define AL_REVERB_GAINHF 0x0004
+#define AL_REVERB_DECAY_TIME 0x0005
+#define AL_REVERB_DECAY_HFRATIO 0x0006
+#define AL_REVERB_REFLECTIONS_GAIN 0x0007
+#define AL_REVERB_REFLECTIONS_DELAY 0x0008
+#define AL_REVERB_LATE_REVERB_GAIN 0x0009
+#define AL_REVERB_LATE_REVERB_DELAY 0x000A
+#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B
+#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C
+#define AL_REVERB_DECAY_HFLIMIT 0x000D
+
+/* EAX Reverb effect parameters */
+#define AL_EAXREVERB_DENSITY 0x0001
+#define AL_EAXREVERB_DIFFUSION 0x0002
+#define AL_EAXREVERB_GAIN 0x0003
+#define AL_EAXREVERB_GAINHF 0x0004
+#define AL_EAXREVERB_GAINLF 0x0005
+#define AL_EAXREVERB_DECAY_TIME 0x0006
+#define AL_EAXREVERB_DECAY_HFRATIO 0x0007
+#define AL_EAXREVERB_DECAY_LFRATIO 0x0008
+#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009
+#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A
+#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B
+#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C
+#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D
+#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E
+#define AL_EAXREVERB_ECHO_TIME 0x000F
+#define AL_EAXREVERB_ECHO_DEPTH 0x0010
+#define AL_EAXREVERB_MODULATION_TIME 0x0011
+#define AL_EAXREVERB_MODULATION_DEPTH 0x0012
+#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013
+#define AL_EAXREVERB_HFREFERENCE 0x0014
+#define AL_EAXREVERB_LFREFERENCE 0x0015
+#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016
+#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017
+
+/* Chorus effect parameters */
+#define AL_CHORUS_WAVEFORM 0x0001
+#define AL_CHORUS_PHASE 0x0002
+#define AL_CHORUS_RATE 0x0003
+#define AL_CHORUS_DEPTH 0x0004
+#define AL_CHORUS_FEEDBACK 0x0005
+#define AL_CHORUS_DELAY 0x0006
+
+/* Distortion effect parameters */
+#define AL_DISTORTION_EDGE 0x0001
+#define AL_DISTORTION_GAIN 0x0002
+#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003
+#define AL_DISTORTION_EQCENTER 0x0004
+#define AL_DISTORTION_EQBANDWIDTH 0x0005
+
+/* Echo effect parameters */
+#define AL_ECHO_DELAY 0x0001
+#define AL_ECHO_LRDELAY 0x0002
+#define AL_ECHO_DAMPING 0x0003
+#define AL_ECHO_FEEDBACK 0x0004
+#define AL_ECHO_SPREAD 0x0005
+
+/* Flanger effect parameters */
+#define AL_FLANGER_WAVEFORM 0x0001
+#define AL_FLANGER_PHASE 0x0002
+#define AL_FLANGER_RATE 0x0003
+#define AL_FLANGER_DEPTH 0x0004
+#define AL_FLANGER_FEEDBACK 0x0005
+#define AL_FLANGER_DELAY 0x0006
+
+/* Frequency shifter effect parameters */
+#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001
+#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002
+#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003
+
+/* Vocal morpher effect parameters */
+#define AL_VOCAL_MORPHER_PHONEMEA 0x0001
+#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002
+#define AL_VOCAL_MORPHER_PHONEMEB 0x0003
+#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004
+#define AL_VOCAL_MORPHER_WAVEFORM 0x0005
+#define AL_VOCAL_MORPHER_RATE 0x0006
+
+/* Pitchshifter effect parameters */
+#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001
+#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002
+
+/* Ringmodulator effect parameters */
+#define AL_RING_MODULATOR_FREQUENCY 0x0001
+#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002
+#define AL_RING_MODULATOR_WAVEFORM 0x0003
+
+/* Autowah effect parameters */
+#define AL_AUTOWAH_ATTACK_TIME 0x0001
+#define AL_AUTOWAH_RELEASE_TIME 0x0002
+#define AL_AUTOWAH_RESONANCE 0x0003
+#define AL_AUTOWAH_PEAK_GAIN 0x0004
+
+/* Compressor effect parameters */
+#define AL_COMPRESSOR_ONOFF 0x0001
+
+/* Equalizer effect parameters */
+#define AL_EQUALIZER_LOW_GAIN 0x0001
+#define AL_EQUALIZER_LOW_CUTOFF 0x0002
+#define AL_EQUALIZER_MID1_GAIN 0x0003
+#define AL_EQUALIZER_MID1_CENTER 0x0004
+#define AL_EQUALIZER_MID1_WIDTH 0x0005
+#define AL_EQUALIZER_MID2_GAIN 0x0006
+#define AL_EQUALIZER_MID2_CENTER 0x0007
+#define AL_EQUALIZER_MID2_WIDTH 0x0008
+#define AL_EQUALIZER_HIGH_GAIN 0x0009
+#define AL_EQUALIZER_HIGH_CUTOFF 0x000A
+
+/* Effect type */
+#define AL_EFFECT_FIRST_PARAMETER 0x0000
+#define AL_EFFECT_LAST_PARAMETER 0x8000
+#define AL_EFFECT_TYPE 0x8001
+
+/* Effect types, used with the AL_EFFECT_TYPE property */
+#define AL_EFFECT_NULL 0x0000
+#define AL_EFFECT_REVERB 0x0001
+#define AL_EFFECT_CHORUS 0x0002
+#define AL_EFFECT_DISTORTION 0x0003
+#define AL_EFFECT_ECHO 0x0004
+#define AL_EFFECT_FLANGER 0x0005
+#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006
+#define AL_EFFECT_VOCAL_MORPHER 0x0007
+#define AL_EFFECT_PITCH_SHIFTER 0x0008
+#define AL_EFFECT_RING_MODULATOR 0x0009
+#define AL_EFFECT_AUTOWAH 0x000A
+#define AL_EFFECT_COMPRESSOR 0x000B
+#define AL_EFFECT_EQUALIZER 0x000C
+#define AL_EFFECT_EAXREVERB 0x8000
+
+/* Auxiliary Effect Slot properties. */
+#define AL_EFFECTSLOT_EFFECT 0x0001
+#define AL_EFFECTSLOT_GAIN 0x0002
+#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003
+
+/* NULL Auxiliary Slot ID to disable a source send. */
+#define AL_EFFECTSLOT_NULL 0x0000
+
+
+/* Filter properties. */
+
+/* Lowpass filter parameters */
+#define AL_LOWPASS_GAIN 0x0001
+#define AL_LOWPASS_GAINHF 0x0002
+
+/* Highpass filter parameters */
+#define AL_HIGHPASS_GAIN 0x0001
+#define AL_HIGHPASS_GAINLF 0x0002
+
+/* Bandpass filter parameters */
+#define AL_BANDPASS_GAIN 0x0001
+#define AL_BANDPASS_GAINLF 0x0002
+#define AL_BANDPASS_GAINHF 0x0003
+
+/* Filter type */
+#define AL_FILTER_FIRST_PARAMETER 0x0000
+#define AL_FILTER_LAST_PARAMETER 0x8000
+#define AL_FILTER_TYPE 0x8001
+
+/* Filter types, used with the AL_FILTER_TYPE property */
+#define AL_FILTER_NULL 0x0000
+#define AL_FILTER_LOWPASS 0x0001
+#define AL_FILTER_HIGHPASS 0x0002
+#define AL_FILTER_BANDPASS 0x0003
+
+
+/* Effect object function types. */
+typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*);
+typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint);
+typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*);
+typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat);
+typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*);
+typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*);
+
+/* Filter object function types. */
+typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*);
+typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint);
+typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*);
+typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat);
+typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*);
+typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*);
+
+/* Auxiliary Effect Slot object function types. */
+typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*);
+typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*);
+
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
+AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects);
+AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect);
+AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue);
+AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues);
+AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues);
+AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue);
+AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
+
+AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
+AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters);
+AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter);
+AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue);
+AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues);
+AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues);
+AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue);
+AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
+
+AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
+AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots);
+AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
+#endif
+
+/* Filter ranges and defaults. */
+
+/* Lowpass filter */
+#define AL_LOWPASS_MIN_GAIN (0.0f)
+#define AL_LOWPASS_MAX_GAIN (1.0f)
+#define AL_LOWPASS_DEFAULT_GAIN (1.0f)
+
+#define AL_LOWPASS_MIN_GAINHF (0.0f)
+#define AL_LOWPASS_MAX_GAINHF (1.0f)
+#define AL_LOWPASS_DEFAULT_GAINHF (1.0f)
+
+/* Highpass filter */
+#define AL_HIGHPASS_MIN_GAIN (0.0f)
+#define AL_HIGHPASS_MAX_GAIN (1.0f)
+#define AL_HIGHPASS_DEFAULT_GAIN (1.0f)
+
+#define AL_HIGHPASS_MIN_GAINLF (0.0f)
+#define AL_HIGHPASS_MAX_GAINLF (1.0f)
+#define AL_HIGHPASS_DEFAULT_GAINLF (1.0f)
+
+/* Bandpass filter */
+#define AL_BANDPASS_MIN_GAIN (0.0f)
+#define AL_BANDPASS_MAX_GAIN (1.0f)
+#define AL_BANDPASS_DEFAULT_GAIN (1.0f)
+
+#define AL_BANDPASS_MIN_GAINHF (0.0f)
+#define AL_BANDPASS_MAX_GAINHF (1.0f)
+#define AL_BANDPASS_DEFAULT_GAINHF (1.0f)
+
+#define AL_BANDPASS_MIN_GAINLF (0.0f)
+#define AL_BANDPASS_MAX_GAINLF (1.0f)
+#define AL_BANDPASS_DEFAULT_GAINLF (1.0f)
+
+
+/* Effect parameter ranges and defaults. */
+
+/* Standard reverb effect */
+#define AL_REVERB_MIN_DENSITY (0.0f)
+#define AL_REVERB_MAX_DENSITY (1.0f)
+#define AL_REVERB_DEFAULT_DENSITY (1.0f)
+
+#define AL_REVERB_MIN_DIFFUSION (0.0f)
+#define AL_REVERB_MAX_DIFFUSION (1.0f)
+#define AL_REVERB_DEFAULT_DIFFUSION (1.0f)
+
+#define AL_REVERB_MIN_GAIN (0.0f)
+#define AL_REVERB_MAX_GAIN (1.0f)
+#define AL_REVERB_DEFAULT_GAIN (0.32f)
+
+#define AL_REVERB_MIN_GAINHF (0.0f)
+#define AL_REVERB_MAX_GAINHF (1.0f)
+#define AL_REVERB_DEFAULT_GAINHF (0.89f)
+
+#define AL_REVERB_MIN_DECAY_TIME (0.1f)
+#define AL_REVERB_MAX_DECAY_TIME (20.0f)
+#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f)
+
+#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f)
+#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f)
+#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f)
+
+#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f)
+#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f)
+#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f)
+
+#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f)
+#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f)
+#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f)
+
+#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f)
+#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f)
+#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f)
+
+#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f)
+#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f)
+#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f)
+
+#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f)
+#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f)
+#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
+
+#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
+#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
+#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
+
+#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE
+#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE
+#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE
+
+/* EAX reverb effect */
+#define AL_EAXREVERB_MIN_DENSITY (0.0f)
+#define AL_EAXREVERB_MAX_DENSITY (1.0f)
+#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f)
+
+#define AL_EAXREVERB_MIN_DIFFUSION (0.0f)
+#define AL_EAXREVERB_MAX_DIFFUSION (1.0f)
+#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f)
+
+#define AL_EAXREVERB_MIN_GAIN (0.0f)
+#define AL_EAXREVERB_MAX_GAIN (1.0f)
+#define AL_EAXREVERB_DEFAULT_GAIN (0.32f)
+
+#define AL_EAXREVERB_MIN_GAINHF (0.0f)
+#define AL_EAXREVERB_MAX_GAINHF (1.0f)
+#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f)
+
+#define AL_EAXREVERB_MIN_GAINLF (0.0f)
+#define AL_EAXREVERB_MAX_GAINLF (1.0f)
+#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f)
+
+#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f)
+#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f)
+#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f)
+
+#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f)
+#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f)
+#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f)
+
+#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f)
+#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f)
+#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f)
+
+#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f)
+#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f)
+#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f)
+
+#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f)
+#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f)
+#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f)
+
+#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f)
+
+#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f)
+#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f)
+#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f)
+
+#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f)
+#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f)
+#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f)
+
+#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f)
+
+#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f)
+#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f)
+#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f)
+
+#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f)
+#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f)
+#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f)
+
+#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f)
+#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f)
+#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f)
+
+#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f)
+#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f)
+#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f)
+
+#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f)
+#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f)
+#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
+
+#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f)
+#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f)
+#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f)
+
+#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f)
+#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f)
+#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f)
+
+#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
+#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
+#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
+
+#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE
+#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE
+#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE
+
+/* Chorus effect */
+#define AL_CHORUS_WAVEFORM_SINUSOID (0)
+#define AL_CHORUS_WAVEFORM_TRIANGLE (1)
+
+#define AL_CHORUS_MIN_WAVEFORM (0)
+#define AL_CHORUS_MAX_WAVEFORM (1)
+#define AL_CHORUS_DEFAULT_WAVEFORM (1)
+
+#define AL_CHORUS_MIN_PHASE (-180)
+#define AL_CHORUS_MAX_PHASE (180)
+#define AL_CHORUS_DEFAULT_PHASE (90)
+
+#define AL_CHORUS_MIN_RATE (0.0f)
+#define AL_CHORUS_MAX_RATE (10.0f)
+#define AL_CHORUS_DEFAULT_RATE (1.1f)
+
+#define AL_CHORUS_MIN_DEPTH (0.0f)
+#define AL_CHORUS_MAX_DEPTH (1.0f)
+#define AL_CHORUS_DEFAULT_DEPTH (0.1f)
+
+#define AL_CHORUS_MIN_FEEDBACK (-1.0f)
+#define AL_CHORUS_MAX_FEEDBACK (1.0f)
+#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f)
+
+#define AL_CHORUS_MIN_DELAY (0.0f)
+#define AL_CHORUS_MAX_DELAY (0.016f)
+#define AL_CHORUS_DEFAULT_DELAY (0.016f)
+
+/* Distortion effect */
+#define AL_DISTORTION_MIN_EDGE (0.0f)
+#define AL_DISTORTION_MAX_EDGE (1.0f)
+#define AL_DISTORTION_DEFAULT_EDGE (0.2f)
+
+#define AL_DISTORTION_MIN_GAIN (0.01f)
+#define AL_DISTORTION_MAX_GAIN (1.0f)
+#define AL_DISTORTION_DEFAULT_GAIN (0.05f)
+
+#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f)
+#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f)
+#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f)
+
+#define AL_DISTORTION_MIN_EQCENTER (80.0f)
+#define AL_DISTORTION_MAX_EQCENTER (24000.0f)
+#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f)
+
+#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f)
+#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f)
+#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f)
+
+/* Echo effect */
+#define AL_ECHO_MIN_DELAY (0.0f)
+#define AL_ECHO_MAX_DELAY (0.207f)
+#define AL_ECHO_DEFAULT_DELAY (0.1f)
+
+#define AL_ECHO_MIN_LRDELAY (0.0f)
+#define AL_ECHO_MAX_LRDELAY (0.404f)
+#define AL_ECHO_DEFAULT_LRDELAY (0.1f)
+
+#define AL_ECHO_MIN_DAMPING (0.0f)
+#define AL_ECHO_MAX_DAMPING (0.99f)
+#define AL_ECHO_DEFAULT_DAMPING (0.5f)
+
+#define AL_ECHO_MIN_FEEDBACK (0.0f)
+#define AL_ECHO_MAX_FEEDBACK (1.0f)
+#define AL_ECHO_DEFAULT_FEEDBACK (0.5f)
+
+#define AL_ECHO_MIN_SPREAD (-1.0f)
+#define AL_ECHO_MAX_SPREAD (1.0f)
+#define AL_ECHO_DEFAULT_SPREAD (-1.0f)
+
+/* Flanger effect */
+#define AL_FLANGER_WAVEFORM_SINUSOID (0)
+#define AL_FLANGER_WAVEFORM_TRIANGLE (1)
+
+#define AL_FLANGER_MIN_WAVEFORM (0)
+#define AL_FLANGER_MAX_WAVEFORM (1)
+#define AL_FLANGER_DEFAULT_WAVEFORM (1)
+
+#define AL_FLANGER_MIN_PHASE (-180)
+#define AL_FLANGER_MAX_PHASE (180)
+#define AL_FLANGER_DEFAULT_PHASE (0)
+
+#define AL_FLANGER_MIN_RATE (0.0f)
+#define AL_FLANGER_MAX_RATE (10.0f)
+#define AL_FLANGER_DEFAULT_RATE (0.27f)
+
+#define AL_FLANGER_MIN_DEPTH (0.0f)
+#define AL_FLANGER_MAX_DEPTH (1.0f)
+#define AL_FLANGER_DEFAULT_DEPTH (1.0f)
+
+#define AL_FLANGER_MIN_FEEDBACK (-1.0f)
+#define AL_FLANGER_MAX_FEEDBACK (1.0f)
+#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f)
+
+#define AL_FLANGER_MIN_DELAY (0.0f)
+#define AL_FLANGER_MAX_DELAY (0.004f)
+#define AL_FLANGER_DEFAULT_DELAY (0.002f)
+
+/* Frequency shifter effect */
+#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f)
+#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f)
+#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f)
+
+#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0)
+#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2)
+#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0)
+
+#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0)
+#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1)
+#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2)
+
+#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0)
+#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2)
+#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0)
+
+/* Vocal morpher effect */
+#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0)
+
+#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0)
+
+#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10)
+
+#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0)
+
+#define AL_VOCAL_MORPHER_PHONEME_A (0)
+#define AL_VOCAL_MORPHER_PHONEME_E (1)
+#define AL_VOCAL_MORPHER_PHONEME_I (2)
+#define AL_VOCAL_MORPHER_PHONEME_O (3)
+#define AL_VOCAL_MORPHER_PHONEME_U (4)
+#define AL_VOCAL_MORPHER_PHONEME_AA (5)
+#define AL_VOCAL_MORPHER_PHONEME_AE (6)
+#define AL_VOCAL_MORPHER_PHONEME_AH (7)
+#define AL_VOCAL_MORPHER_PHONEME_AO (8)
+#define AL_VOCAL_MORPHER_PHONEME_EH (9)
+#define AL_VOCAL_MORPHER_PHONEME_ER (10)
+#define AL_VOCAL_MORPHER_PHONEME_IH (11)
+#define AL_VOCAL_MORPHER_PHONEME_IY (12)
+#define AL_VOCAL_MORPHER_PHONEME_UH (13)
+#define AL_VOCAL_MORPHER_PHONEME_UW (14)
+#define AL_VOCAL_MORPHER_PHONEME_B (15)
+#define AL_VOCAL_MORPHER_PHONEME_D (16)
+#define AL_VOCAL_MORPHER_PHONEME_F (17)
+#define AL_VOCAL_MORPHER_PHONEME_G (18)
+#define AL_VOCAL_MORPHER_PHONEME_J (19)
+#define AL_VOCAL_MORPHER_PHONEME_K (20)
+#define AL_VOCAL_MORPHER_PHONEME_L (21)
+#define AL_VOCAL_MORPHER_PHONEME_M (22)
+#define AL_VOCAL_MORPHER_PHONEME_N (23)
+#define AL_VOCAL_MORPHER_PHONEME_P (24)
+#define AL_VOCAL_MORPHER_PHONEME_R (25)
+#define AL_VOCAL_MORPHER_PHONEME_S (26)
+#define AL_VOCAL_MORPHER_PHONEME_T (27)
+#define AL_VOCAL_MORPHER_PHONEME_V (28)
+#define AL_VOCAL_MORPHER_PHONEME_Z (29)
+
+#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0)
+#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1)
+#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2)
+
+#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0)
+#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2)
+#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0)
+
+#define AL_VOCAL_MORPHER_MIN_RATE (0.0f)
+#define AL_VOCAL_MORPHER_MAX_RATE (10.0f)
+#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f)
+
+/* Pitch shifter effect */
+#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12)
+#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12)
+#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12)
+
+#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50)
+#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50)
+#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0)
+
+/* Ring modulator effect */
+#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f)
+#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f)
+#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f)
+
+#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f)
+#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f)
+#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f)
+
+#define AL_RING_MODULATOR_SINUSOID (0)
+#define AL_RING_MODULATOR_SAWTOOTH (1)
+#define AL_RING_MODULATOR_SQUARE (2)
+
+#define AL_RING_MODULATOR_MIN_WAVEFORM (0)
+#define AL_RING_MODULATOR_MAX_WAVEFORM (2)
+#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0)
+
+/* Autowah effect */
+#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f)
+#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f)
+#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f)
+
+#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f)
+#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f)
+#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f)
+
+#define AL_AUTOWAH_MIN_RESONANCE (2.0f)
+#define AL_AUTOWAH_MAX_RESONANCE (1000.0f)
+#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f)
+
+#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f)
+#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f)
+#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f)
+
+/* Compressor effect */
+#define AL_COMPRESSOR_MIN_ONOFF (0)
+#define AL_COMPRESSOR_MAX_ONOFF (1)
+#define AL_COMPRESSOR_DEFAULT_ONOFF (1)
+
+/* Equalizer effect */
+#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f)
+#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f)
+#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f)
+
+#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f)
+#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f)
+#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f)
+
+#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f)
+#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f)
+#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f)
+
+#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f)
+#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f)
+#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f)
+
+#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f)
+#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f)
+#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f)
+
+#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f)
+#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f)
+#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f)
+
+#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f)
+#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f)
+#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f)
+
+#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f)
+#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f)
+#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f)
+
+#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f)
+#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f)
+#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f)
+
+#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f)
+#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f)
+#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f)
+
+
+/* Source parameter value ranges and defaults. */
+#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f)
+#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f)
+#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f)
+
+#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
+#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
+#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
+
+#define AL_MIN_CONE_OUTER_GAINHF (0.0f)
+#define AL_MAX_CONE_OUTER_GAINHF (1.0f)
+#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f)
+
+#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE
+#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE
+#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE
+
+#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE
+#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE
+#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE
+
+#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE
+#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE
+#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE
+
+
+/* Listener parameter value ranges and defaults. */
+#define AL_MIN_METERS_PER_UNIT FLT_MIN
+#define AL_MAX_METERS_PER_UNIT FLT_MAX
+#define AL_DEFAULT_METERS_PER_UNIT (1.0f)
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* AL_EFX_H */
diff --git a/src/external/openal_soft/lib/win32/OpenAL32.dll b/src/external/openal_soft/lib/win32/OpenAL32.dll
new file mode 100644
index 00000000..1e3bddd5
--- /dev/null
+++ b/src/external/openal_soft/lib/win32/OpenAL32.dll
Binary files differ
diff --git a/src/external/openal_soft/lib/win32/libOpenAL32.a b/src/external/openal_soft/lib/win32/libOpenAL32.a
new file mode 100644
index 00000000..3c0df3c7
--- /dev/null
+++ b/src/external/openal_soft/lib/win32/libOpenAL32.a
Binary files differ
diff --git a/src/external/openal_soft/lib/win32/libOpenAL32dll.a b/src/external/openal_soft/lib/win32/libOpenAL32dll.a
new file mode 100644
index 00000000..1c4c63c8
--- /dev/null
+++ b/src/external/openal_soft/lib/win32/libOpenAL32dll.a
Binary files differ
diff --git a/src/external/pthread/COPYING b/src/external/pthread/COPYING
new file mode 100644
index 00000000..5cfea0d0
--- /dev/null
+++ b/src/external/pthread/COPYING
@@ -0,0 +1,150 @@
+ pthreads-win32 - a POSIX threads library for Microsoft Windows
+
+
+This file is Copyrighted
+------------------------
+
+ This file is covered under the following Copyright:
+
+ Copyright (C) 2001,2006 Ross P. Johnson
+ All rights reserved.
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+Pthreads-win32 is covered by the GNU Lesser General Public License
+------------------------------------------------------------------
+
+ Pthreads-win32 is open software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation version 2.1 of the
+ License.
+
+ Pthreads-win32 is several binary link libraries, several modules,
+ associated interface definition files and scripts used to control
+ its compilation and installation.
+
+ Pthreads-win32 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ A copy of the GNU Lesser General Public License is distributed with
+ pthreads-win32 under the filename:
+
+ COPYING.LIB
+
+ You should have received a copy of the version 2.1 GNU Lesser General
+ Public License with pthreads-win32; if not, write to:
+
+ Free Software Foundation, Inc.
+ 59 Temple Place
+ Suite 330
+ Boston, MA 02111-1307
+ USA
+
+ The contact addresses for pthreads-win32 is as follows:
+
+ Web: http://sources.redhat.com/pthreads-win32
+ Email: Ross Johnson
+ Please use: Firstname.Lastname@homemail.com.au
+
+
+
+Pthreads-win32 copyrights and exception files
+---------------------------------------------
+
+ With the exception of the files listed below, Pthreads-win32
+ is covered under the following GNU Lesser General Public License
+ Copyrights:
+
+ Pthreads-win32 - POSIX Threads Library for Win32
+ Copyright(C) 1998 John E. Bossom
+ Copyright(C) 1999,2006 Pthreads-win32 contributors
+
+ The current list of contributors is contained
+ in the file CONTRIBUTORS included with the source
+ code distribution. The current list of CONTRIBUTORS
+ can also be seen at the following WWW location:
+ http://sources.redhat.com/pthreads-win32/contributors.html
+
+ Contact Email: Ross Johnson
+ Please use: Firstname.Lastname@homemail.com.au
+
+ These files are not covered under one of the Copyrights listed above:
+
+ COPYING
+ COPYING.LIB
+ tests/rwlock7.c
+
+ This file, COPYING, is distributed under the Copyright found at the
+ top of this file. It is important to note that you may distribute
+ verbatim copies of this file but you may not modify this file.
+
+ The file COPYING.LIB, which contains a copy of the version 2.1
+ GNU Lesser General Public License, is itself copyrighted by the
+ Free Software Foundation, Inc. Please note that the Free Software
+ Foundation, Inc. does NOT have a copyright over Pthreads-win32,
+ only the COPYING.LIB that is supplied with pthreads-win32.
+
+ The file tests/rwlock7.c is derived from code written by
+ Dave Butenhof for his book 'Programming With POSIX(R) Threads'.
+ The original code was obtained by free download from his website
+ http://home.earthlink.net/~anneart/family/Threads/source.html
+ and did not contain a copyright or author notice. It is assumed to
+ be freely distributable.
+
+ In all cases one may use and distribute these exception files freely.
+ And because one may freely distribute the LGPL covered files, the
+ entire pthreads-win32 source may be freely used and distributed.
+
+
+
+General Copyleft and License info
+---------------------------------
+
+ For general information on Copylefts, see:
+
+ http://www.gnu.org/copyleft/
+
+ For information on GNU Lesser General Public Licenses, see:
+
+ http://www.gnu.org/copyleft/lesser.html
+ http://www.gnu.org/copyleft/lesser.txt
+
+
+Why pthreads-win32 did not use the GNU General Public License
+-------------------------------------------------------------
+
+ The goal of the pthreads-win32 project has been to
+ provide a quality and complete implementation of the POSIX
+ threads API for Microsoft Windows within the limits imposed
+ by virtue of it being a stand-alone library and not
+ linked directly to other POSIX compliant libraries. For
+ example, some functions and features, such as those based
+ on POSIX signals, are missing.
+
+ Pthreads-win32 is a library, available in several different
+ versions depending on supported compilers, and may be used
+ as a dynamically linked module or a statically linked set of
+ binary modules. It is not an application on it's own.
+
+ It was fully intended that pthreads-win32 be usable with
+ commercial software not covered by either the GPL or the LGPL
+ licenses. Pthreads-win32 has many contributors to it's
+ code base, many of whom have done so because they have
+ used the library in commercial or proprietry software
+ projects.
+
+ Releasing pthreads-win32 under the LGPL ensures that the
+ library can be used widely, while at the same time ensures
+ that bug fixes and improvements to the pthreads-win32 code
+ itself is returned to benefit all current and future users
+ of the library.
+
+ Although pthreads-win32 makes it possible for applications
+ that use POSIX threads to be ported to Win32 platforms, the
+ broader goal of the project is to encourage the use of open
+ standards, and in particular, to make it just a little easier
+ for developers writing Win32 applications to consider
+ widening the potential market for their products.
diff --git a/src/external/pthread/include/pthread.h b/src/external/pthread/include/pthread.h
new file mode 100644
index 00000000..b4072f72
--- /dev/null
+++ b/src/external/pthread/include/pthread.h
@@ -0,0 +1,1368 @@
+/* This is an implementation of the threads API of POSIX 1003.1-2001.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2005 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@callisto.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#if !defined( PTHREAD_H )
+#define PTHREAD_H
+
+/*
+ * See the README file for an explanation of the pthreads-win32 version
+ * numbering scheme and how the DLL is named etc.
+ */
+#define PTW32_VERSION 2,9,1,0
+#define PTW32_VERSION_STRING "2, 9, 1, 0\0"
+
+/* There are three implementations of cancel cleanup.
+ * Note that pthread.h is included in both application
+ * compilation units and also internally for the library.
+ * The code here and within the library aims to work
+ * for all reasonable combinations of environments.
+ *
+ * The three implementations are:
+ *
+ * WIN32 SEH
+ * C
+ * C++
+ *
+ * Please note that exiting a push/pop block via
+ * "return", "exit", "break", or "continue" will
+ * lead to different behaviour amongst applications
+ * depending upon whether the library was built
+ * using SEH, C++, or C. For example, a library built
+ * with SEH will call the cleanup routine, while both
+ * C++ and C built versions will not.
+ */
+
+/*
+ * Define defaults for cleanup code.
+ * Note: Unless the build explicitly defines one of the following, then
+ * we default to standard C style cleanup. This style uses setjmp/longjmp
+ * in the cancelation and thread exit implementations and therefore won't
+ * do stack unwinding if linked to applications that have it (e.g.
+ * C++ apps). This is currently consistent with most/all commercial Unix
+ * POSIX threads implementations.
+ */
+#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C )
+# define __CLEANUP_C
+#endif
+
+#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC))
+#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler.
+#endif
+
+/*
+ * Stop here if we are being included by the resource compiler.
+ */
+#if !defined(RC_INVOKED)
+
+#undef PTW32_LEVEL
+
+#if defined(_POSIX_SOURCE)
+#define PTW32_LEVEL 0
+/* Early POSIX */
+#endif
+
+#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
+#undef PTW32_LEVEL
+#define PTW32_LEVEL 1
+/* Include 1b, 1c and 1d */
+#endif
+
+#if defined(INCLUDE_NP)
+#undef PTW32_LEVEL
+#define PTW32_LEVEL 2
+/* Include Non-Portable extensions */
+#endif
+
+#define PTW32_LEVEL_MAX 3
+
+#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_LEVEL)
+#define PTW32_LEVEL PTW32_LEVEL_MAX
+/* Include everything */
+#endif
+
+#if defined(_UWIN)
+# define HAVE_STRUCT_TIMESPEC 1
+# define HAVE_SIGNAL_H 1
+# undef HAVE_PTW32_CONFIG_H
+# pragma comment(lib, "pthread")
+#endif
+
+/*
+ * -------------------------------------------------------------
+ *
+ *
+ * Module: pthread.h
+ *
+ * Purpose:
+ * Provides an implementation of PThreads based upon the
+ * standard:
+ *
+ * POSIX 1003.1-2001
+ * and
+ * The Single Unix Specification version 3
+ *
+ * (these two are equivalent)
+ *
+ * in order to enhance code portability between Windows,
+ * various commercial Unix implementations, and Linux.
+ *
+ * See the ANNOUNCE file for a full list of conforming
+ * routines and defined constants, and a list of missing
+ * routines and constants not defined in this implementation.
+ *
+ * Authors:
+ * There have been many contributors to this library.
+ * The initial implementation was contributed by
+ * John Bossom, and several others have provided major
+ * sections or revisions of parts of the implementation.
+ * Often significant effort has been contributed to
+ * find and fix important bugs and other problems to
+ * improve the reliability of the library, which sometimes
+ * is not reflected in the amount of code which changed as
+ * result.
+ * As much as possible, the contributors are acknowledged
+ * in the ChangeLog file in the source code distribution
+ * where their changes are noted in detail.
+ *
+ * Contributors are listed in the CONTRIBUTORS file.
+ *
+ * As usual, all bouquets go to the contributors, and all
+ * brickbats go to the project maintainer.
+ *
+ * Maintainer:
+ * The code base for this project is coordinated and
+ * eventually pre-tested, packaged, and made available by
+ *
+ * Ross Johnson <rpj@callisto.canberra.edu.au>
+ *
+ * QA Testers:
+ * Ultimately, the library is tested in the real world by
+ * a host of competent and demanding scientists and
+ * engineers who report bugs and/or provide solutions
+ * which are then fixed or incorporated into subsequent
+ * versions of the library. Each time a bug is fixed, a
+ * test case is written to prove the fix and ensure
+ * that later changes to the code don't reintroduce the
+ * same error. The number of test cases is slowly growing
+ * and therefore so is the code reliability.
+ *
+ * Compliance:
+ * See the file ANNOUNCE for the list of implemented
+ * and not-implemented routines and defined options.
+ * Of course, these are all defined is this file as well.
+ *
+ * Web site:
+ * The source code and other information about this library
+ * are available from
+ *
+ * http://sources.redhat.com/pthreads-win32/
+ *
+ * -------------------------------------------------------------
+ */
+
+/* Try to avoid including windows.h */
+#if (defined(__MINGW64__) || defined(__MINGW32__)) && defined(__cplusplus)
+#define PTW32_INCLUDE_WINDOWS_H
+#endif
+
+#if defined(PTW32_INCLUDE_WINDOWS_H)
+#include <windows.h>
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__)
+/*
+ * VC++6.0 or early compiler's header has no DWORD_PTR type.
+ */
+typedef unsigned long DWORD_PTR;
+typedef unsigned long ULONG_PTR;
+#endif
+/*
+ * -----------------
+ * autoconf switches
+ * -----------------
+ */
+
+#if defined(HAVE_PTW32_CONFIG_H)
+#include "config.h"
+#endif /* HAVE_PTW32_CONFIG_H */
+
+#if !defined(NEED_FTIME)
+#include <time.h>
+#else /* NEED_FTIME */
+/* use native WIN32 time API */
+#endif /* NEED_FTIME */
+
+#if defined(HAVE_SIGNAL_H)
+#include <signal.h>
+#endif /* HAVE_SIGNAL_H */
+
+#include <limits.h>
+
+/*
+ * Boolean values to make us independent of system includes.
+ */
+enum {
+ PTW32_FALSE = 0,
+ PTW32_TRUE = (! PTW32_FALSE)
+};
+
+/*
+ * This is a duplicate of what is in the autoconf config.h,
+ * which is only used when building the pthread-win32 libraries.
+ */
+
+#if !defined(PTW32_CONFIG_H)
+# if defined(WINCE)
+# define NEED_ERRNO
+# define NEED_SEM
+# endif
+# if defined(__MINGW64__)
+# define HAVE_STRUCT_TIMESPEC
+# define HAVE_MODE_T
+# elif defined(_UWIN) || defined(__MINGW32__)
+# define HAVE_MODE_T
+# endif
+#endif
+
+/*
+ *
+ */
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+#if defined(NEED_ERRNO)
+#include "need_errno.h"
+#else
+#include <errno.h>
+#endif
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+/*
+ * Several systems don't define some error numbers.
+ */
+#if !defined(ENOTSUP)
+# define ENOTSUP 48 /* This is the value in Solaris. */
+#endif
+
+#if !defined(ETIMEDOUT)
+# define ETIMEDOUT 10060 /* Same as WSAETIMEDOUT */
+#endif
+
+#if !defined(ENOSYS)
+# define ENOSYS 140 /* Semi-arbitrary value */
+#endif
+
+#if !defined(EDEADLK)
+# if defined(EDEADLOCK)
+# define EDEADLK EDEADLOCK
+# else
+# define EDEADLK 36 /* This is the value in MSVC. */
+# endif
+#endif
+
+/* POSIX 2008 - related to robust mutexes */
+#if !defined(EOWNERDEAD)
+# define EOWNERDEAD 43
+#endif
+#if !defined(ENOTRECOVERABLE)
+# define ENOTRECOVERABLE 44
+#endif
+
+#include <sched.h>
+
+/*
+ * To avoid including windows.h we define only those things that we
+ * actually need from it.
+ */
+#if !defined(PTW32_INCLUDE_WINDOWS_H)
+#if !defined(HANDLE)
+# define PTW32__HANDLE_DEF
+# define HANDLE void *
+#endif
+#if !defined(DWORD)
+# define PTW32__DWORD_DEF
+# define DWORD unsigned long
+#endif
+#endif
+
+#if !defined(HAVE_STRUCT_TIMESPEC)
+#define HAVE_STRUCT_TIMESPEC
+#if !defined(_TIMESPEC_DEFINED)
+#define _TIMESPEC_DEFINED
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+#endif /* _TIMESPEC_DEFINED */
+#endif /* HAVE_STRUCT_TIMESPEC */
+
+#if !defined(SIG_BLOCK)
+#define SIG_BLOCK 0
+#endif /* SIG_BLOCK */
+
+#if !defined(SIG_UNBLOCK)
+#define SIG_UNBLOCK 1
+#endif /* SIG_UNBLOCK */
+
+#if !defined(SIG_SETMASK)
+#define SIG_SETMASK 2
+#endif /* SIG_SETMASK */
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * -------------------------------------------------------------
+ *
+ * POSIX 1003.1-2001 Options
+ * =========================
+ *
+ * Options are normally set in <unistd.h>, which is not provided
+ * with pthreads-win32.
+ *
+ * For conformance with the Single Unix Specification (version 3), all of the
+ * options below are defined, and have a value of either -1 (not supported)
+ * or 200112L (supported).
+ *
+ * These options can neither be left undefined nor have a value of 0, because
+ * either indicates that sysconf(), which is not implemented, may be used at
+ * runtime to check the status of the option.
+ *
+ * _POSIX_THREADS (== 200112L)
+ * If == 200112L, you can use threads
+ *
+ * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L)
+ * If == 200112L, you can control the size of a thread's
+ * stack
+ * pthread_attr_getstacksize
+ * pthread_attr_setstacksize
+ *
+ * _POSIX_THREAD_ATTR_STACKADDR (== -1)
+ * If == 200112L, you can allocate and control a thread's
+ * stack. If not supported, the following functions
+ * will return ENOSYS, indicating they are not
+ * supported:
+ * pthread_attr_getstackaddr
+ * pthread_attr_setstackaddr
+ *
+ * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1)
+ * If == 200112L, you can use realtime scheduling.
+ * This option indicates that the behaviour of some
+ * implemented functions conforms to the additional TPS
+ * requirements in the standard. E.g. rwlocks favour
+ * writers over readers when threads have equal priority.
+ *
+ * _POSIX_THREAD_PRIO_INHERIT (== -1)
+ * If == 200112L, you can create priority inheritance
+ * mutexes.
+ * pthread_mutexattr_getprotocol +
+ * pthread_mutexattr_setprotocol +
+ *
+ * _POSIX_THREAD_PRIO_PROTECT (== -1)
+ * If == 200112L, you can create priority ceiling mutexes
+ * Indicates the availability of:
+ * pthread_mutex_getprioceiling
+ * pthread_mutex_setprioceiling
+ * pthread_mutexattr_getprioceiling
+ * pthread_mutexattr_getprotocol +
+ * pthread_mutexattr_setprioceiling
+ * pthread_mutexattr_setprotocol +
+ *
+ * _POSIX_THREAD_PROCESS_SHARED (== -1)
+ * If set, you can create mutexes and condition
+ * variables that can be shared with another
+ * process.If set, indicates the availability
+ * of:
+ * pthread_mutexattr_getpshared
+ * pthread_mutexattr_setpshared
+ * pthread_condattr_getpshared
+ * pthread_condattr_setpshared
+ *
+ * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L)
+ * If == 200112L you can use the special *_r library
+ * functions that provide thread-safe behaviour
+ *
+ * _POSIX_READER_WRITER_LOCKS (== 200112L)
+ * If == 200112L, you can use read/write locks
+ *
+ * _POSIX_SPIN_LOCKS (== 200112L)
+ * If == 200112L, you can use spin locks
+ *
+ * _POSIX_BARRIERS (== 200112L)
+ * If == 200112L, you can use barriers
+ *
+ * + These functions provide both 'inherit' and/or
+ * 'protect' protocol, based upon these macro
+ * settings.
+ *
+ * -------------------------------------------------------------
+ */
+
+/*
+ * POSIX Options
+ */
+#undef _POSIX_THREADS
+#define _POSIX_THREADS 200809L
+
+#undef _POSIX_READER_WRITER_LOCKS
+#define _POSIX_READER_WRITER_LOCKS 200809L
+
+#undef _POSIX_SPIN_LOCKS
+#define _POSIX_SPIN_LOCKS 200809L
+
+#undef _POSIX_BARRIERS
+#define _POSIX_BARRIERS 200809L
+
+#undef _POSIX_THREAD_SAFE_FUNCTIONS
+#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L
+
+#undef _POSIX_THREAD_ATTR_STACKSIZE
+#define _POSIX_THREAD_ATTR_STACKSIZE 200809L
+
+/*
+ * The following options are not supported
+ */
+#undef _POSIX_THREAD_ATTR_STACKADDR
+#define _POSIX_THREAD_ATTR_STACKADDR -1
+
+#undef _POSIX_THREAD_PRIO_INHERIT
+#define _POSIX_THREAD_PRIO_INHERIT -1
+
+#undef _POSIX_THREAD_PRIO_PROTECT
+#define _POSIX_THREAD_PRIO_PROTECT -1
+
+/* TPS is not fully supported. */
+#undef _POSIX_THREAD_PRIORITY_SCHEDULING
+#define _POSIX_THREAD_PRIORITY_SCHEDULING -1
+
+#undef _POSIX_THREAD_PROCESS_SHARED
+#define _POSIX_THREAD_PROCESS_SHARED -1
+
+
+/*
+ * POSIX 1003.1-2001 Limits
+ * ===========================
+ *
+ * These limits are normally set in <limits.h>, which is not provided with
+ * pthreads-win32.
+ *
+ * PTHREAD_DESTRUCTOR_ITERATIONS
+ * Maximum number of attempts to destroy
+ * a thread's thread-specific data on
+ * termination (must be at least 4)
+ *
+ * PTHREAD_KEYS_MAX
+ * Maximum number of thread-specific data keys
+ * available per process (must be at least 128)
+ *
+ * PTHREAD_STACK_MIN
+ * Minimum supported stack size for a thread
+ *
+ * PTHREAD_THREADS_MAX
+ * Maximum number of threads supported per
+ * process (must be at least 64).
+ *
+ * SEM_NSEMS_MAX
+ * The maximum number of semaphores a process can have.
+ * (must be at least 256)
+ *
+ * SEM_VALUE_MAX
+ * The maximum value a semaphore can have.
+ * (must be at least 32767)
+ *
+ */
+#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
+
+#undef PTHREAD_DESTRUCTOR_ITERATIONS
+#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+
+#undef _POSIX_THREAD_KEYS_MAX
+#define _POSIX_THREAD_KEYS_MAX 128
+
+#undef PTHREAD_KEYS_MAX
+#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX
+
+#undef PTHREAD_STACK_MIN
+#define PTHREAD_STACK_MIN 0
+
+#undef _POSIX_THREAD_THREADS_MAX
+#define _POSIX_THREAD_THREADS_MAX 64
+
+ /* Arbitrary value */
+#undef PTHREAD_THREADS_MAX
+#define PTHREAD_THREADS_MAX 2019
+
+#undef _POSIX_SEM_NSEMS_MAX
+#define _POSIX_SEM_NSEMS_MAX 256
+
+ /* Arbitrary value */
+#undef SEM_NSEMS_MAX
+#define SEM_NSEMS_MAX 1024
+
+#undef _POSIX_SEM_VALUE_MAX
+#define _POSIX_SEM_VALUE_MAX 32767
+
+#undef SEM_VALUE_MAX
+#define SEM_VALUE_MAX INT_MAX
+
+
+#if defined(__GNUC__) && !defined(__declspec)
+# error Please upgrade your GNU compiler to one that supports __declspec.
+#endif
+
+/*
+ * When building the library, you should define PTW32_BUILD so that
+ * the variables/functions are exported correctly. When using the library,
+ * do NOT define PTW32_BUILD, and then the variables/functions will
+ * be imported correctly.
+ */
+#if !defined(PTW32_STATIC_LIB)
+# if defined(PTW32_BUILD)
+# define PTW32_DLLPORT __declspec (dllexport)
+# else
+# define PTW32_DLLPORT __declspec (dllimport)
+# endif
+#else
+# define PTW32_DLLPORT
+#endif
+
+/*
+ * The Open Watcom C/C++ compiler uses a non-standard calling convention
+ * that passes function args in registers unless __cdecl is explicitly specified
+ * in exposed function prototypes.
+ *
+ * We force all calls to cdecl even though this could slow Watcom code down
+ * slightly. If you know that the Watcom compiler will be used to build both
+ * the DLL and application, then you can probably define this as a null string.
+ * Remember that pthread.h (this file) is used for both the DLL and application builds.
+ */
+#define PTW32_CDECL __cdecl
+
+#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX
+# include <sys/types.h>
+#else
+/*
+ * Generic handle type - intended to extend uniqueness beyond
+ * that available with a simple pointer. It should scale for either
+ * IA-32 or IA-64.
+ */
+typedef struct {
+ void * p; /* Pointer to actual object */
+ unsigned int x; /* Extra information - reuse count etc */
+} ptw32_handle_t;
+
+typedef ptw32_handle_t pthread_t;
+typedef struct pthread_attr_t_ * pthread_attr_t;
+typedef struct pthread_once_t_ pthread_once_t;
+typedef struct pthread_key_t_ * pthread_key_t;
+typedef struct pthread_mutex_t_ * pthread_mutex_t;
+typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t;
+typedef struct pthread_cond_t_ * pthread_cond_t;
+typedef struct pthread_condattr_t_ * pthread_condattr_t;
+#endif
+typedef struct pthread_rwlock_t_ * pthread_rwlock_t;
+typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t;
+typedef struct pthread_spinlock_t_ * pthread_spinlock_t;
+typedef struct pthread_barrier_t_ * pthread_barrier_t;
+typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t;
+
+/*
+ * ====================
+ * ====================
+ * POSIX Threads
+ * ====================
+ * ====================
+ */
+
+enum {
+/*
+ * pthread_attr_{get,set}detachstate
+ */
+ PTHREAD_CREATE_JOINABLE = 0, /* Default */
+ PTHREAD_CREATE_DETACHED = 1,
+
+/*
+ * pthread_attr_{get,set}inheritsched
+ */
+ PTHREAD_INHERIT_SCHED = 0,
+ PTHREAD_EXPLICIT_SCHED = 1, /* Default */
+
+/*
+ * pthread_{get,set}scope
+ */
+ PTHREAD_SCOPE_PROCESS = 0,
+ PTHREAD_SCOPE_SYSTEM = 1, /* Default */
+
+/*
+ * pthread_setcancelstate paramters
+ */
+ PTHREAD_CANCEL_ENABLE = 0, /* Default */
+ PTHREAD_CANCEL_DISABLE = 1,
+
+/*
+ * pthread_setcanceltype parameters
+ */
+ PTHREAD_CANCEL_ASYNCHRONOUS = 0,
+ PTHREAD_CANCEL_DEFERRED = 1, /* Default */
+
+/*
+ * pthread_mutexattr_{get,set}pshared
+ * pthread_condattr_{get,set}pshared
+ */
+ PTHREAD_PROCESS_PRIVATE = 0,
+ PTHREAD_PROCESS_SHARED = 1,
+
+/*
+ * pthread_mutexattr_{get,set}robust
+ */
+ PTHREAD_MUTEX_STALLED = 0, /* Default */
+ PTHREAD_MUTEX_ROBUST = 1,
+
+/*
+ * pthread_barrier_wait
+ */
+ PTHREAD_BARRIER_SERIAL_THREAD = -1
+};
+
+/*
+ * ====================
+ * ====================
+ * Cancelation
+ * ====================
+ * ====================
+ */
+#define PTHREAD_CANCELED ((void *)(size_t) -1)
+
+
+/*
+ * ====================
+ * ====================
+ * Once Key
+ * ====================
+ * ====================
+ */
+#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0}
+
+struct pthread_once_t_
+{
+ int done; /* indicates if user function has been executed */
+ void * lock;
+ int reserved1;
+ int reserved2;
+};
+
+
+/*
+ * ====================
+ * ====================
+ * Object initialisers
+ * ====================
+ * ====================
+ */
+#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -1)
+#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -2)
+#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -3)
+
+/*
+ * Compatibility with LinuxThreads
+ */
+#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER
+#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER
+
+#define PTHREAD_COND_INITIALIZER ((pthread_cond_t)(size_t) -1)
+
+#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t)(size_t) -1)
+
+#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t)(size_t) -1)
+
+
+/*
+ * Mutex types.
+ */
+enum
+{
+ /* Compatibility with LinuxThreads */
+ PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP,
+ /* For compatibility with POSIX */
+ PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
+};
+
+
+typedef struct ptw32_cleanup_t ptw32_cleanup_t;
+
+#if defined(_MSC_VER)
+/* Disable MSVC 'anachronism used' warning */
+#pragma warning( disable : 4229 )
+#endif
+
+typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *);
+
+#if defined(_MSC_VER)
+#pragma warning( default : 4229 )
+#endif
+
+struct ptw32_cleanup_t
+{
+ ptw32_cleanup_callback_t routine;
+ void *arg;
+ struct ptw32_cleanup_t *prev;
+};
+
+#if defined(__CLEANUP_SEH)
+ /*
+ * WIN32 SEH version of cancel cleanup.
+ */
+
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ ptw32_cleanup_t _cleanup; \
+ \
+ _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \
+ _cleanup.arg = (_arg); \
+ __try \
+ { \
+
+#define pthread_cleanup_pop( _execute ) \
+ } \
+ __finally \
+ { \
+ if( _execute || AbnormalTermination()) \
+ { \
+ (*(_cleanup.routine))( _cleanup.arg ); \
+ } \
+ } \
+ }
+
+#else /* __CLEANUP_SEH */
+
+#if defined(__CLEANUP_C)
+
+ /*
+ * C implementation of PThreads cancel cleanup
+ */
+
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ ptw32_cleanup_t _cleanup; \
+ \
+ ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \
+
+#define pthread_cleanup_pop( _execute ) \
+ (void) ptw32_pop_cleanup( _execute ); \
+ }
+
+#else /* __CLEANUP_C */
+
+#if defined(__CLEANUP_CXX)
+
+ /*
+ * C++ version of cancel cleanup.
+ * - John E. Bossom.
+ */
+
+ class PThreadCleanup {
+ /*
+ * PThreadCleanup
+ *
+ * Purpose
+ * This class is a C++ helper class that is
+ * used to implement pthread_cleanup_push/
+ * pthread_cleanup_pop.
+ * The destructor of this class automatically
+ * pops the pushed cleanup routine regardless
+ * of how the code exits the scope
+ * (i.e. such as by an exception)
+ */
+ ptw32_cleanup_callback_t cleanUpRout;
+ void * obj;
+ int executeIt;
+
+ public:
+ PThreadCleanup() :
+ cleanUpRout( 0 ),
+ obj( 0 ),
+ executeIt( 0 )
+ /*
+ * No cleanup performed
+ */
+ {
+ }
+
+ PThreadCleanup(
+ ptw32_cleanup_callback_t routine,
+ void * arg ) :
+ cleanUpRout( routine ),
+ obj( arg ),
+ executeIt( 1 )
+ /*
+ * Registers a cleanup routine for 'arg'
+ */
+ {
+ }
+
+ ~PThreadCleanup()
+ {
+ if ( executeIt && ((void *) cleanUpRout != (void *) 0) )
+ {
+ (void) (*cleanUpRout)( obj );
+ }
+ }
+
+ void execute( int exec )
+ {
+ executeIt = exec;
+ }
+ };
+
+ /*
+ * C++ implementation of PThreads cancel cleanup;
+ * This implementation takes advantage of a helper
+ * class who's destructor automatically calls the
+ * cleanup routine if we exit our scope weirdly
+ */
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \
+ (void *) (_arg) );
+
+#define pthread_cleanup_pop( _execute ) \
+ cleanup.execute( _execute ); \
+ }
+
+#else
+
+#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined.
+
+#endif /* __CLEANUP_CXX */
+
+#endif /* __CLEANUP_C */
+
+#endif /* __CLEANUP_SEH */
+
+/*
+ * ===============
+ * ===============
+ * Methods
+ * ===============
+ * ===============
+ */
+
+/*
+ * PThread Attribute Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr,
+ int *detachstate);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr,
+ void **stackaddr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr,
+ size_t * stacksize);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr,
+ int detachstate);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr,
+ void *stackaddr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr,
+ size_t stacksize);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr,
+ struct sched_param *param);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr,
+ const struct sched_param *param);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *,
+ int);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (const pthread_attr_t *,
+ int *);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr,
+ int inheritsched);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(const pthread_attr_t * attr,
+ int * inheritsched);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *,
+ int);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *,
+ int *);
+
+/*
+ * PThread Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid,
+ const pthread_attr_t * attr,
+ void *(PTW32_CDECL *start) (void *),
+ void *arg);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1,
+ pthread_t t2);
+
+PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread,
+ void **value_ptr);
+
+PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state,
+ int *oldstate);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type,
+ int *oldtype);
+
+PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control,
+ void (PTW32_CDECL *init_routine) (void));
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute);
+
+PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup,
+ ptw32_cleanup_callback_t routine,
+ void *arg);
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+/*
+ * Thread Specific Data Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key,
+ void (PTW32_CDECL *destructor) (void *));
+
+PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key,
+ const void *value);
+
+PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key);
+
+
+/*
+ * Mutex Attribute Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t
+ * attr,
+ int *pshared);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr,
+ int pshared);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind);
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (const pthread_mutexattr_t * attr, int *kind);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setrobust(
+ pthread_mutexattr_t *attr,
+ int robust);
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getrobust(
+ const pthread_mutexattr_t * attr,
+ int * robust);
+
+/*
+ * Barrier Attribute Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t
+ * attr,
+ int *pshared);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr,
+ int pshared);
+
+/*
+ * Mutex Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex,
+ const pthread_mutexattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t * mutex,
+ const struct timespec *abstime);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_mutex_consistent (pthread_mutex_t * mutex);
+
+/*
+ * Spinlock Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock);
+
+/*
+ * Barrier Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier,
+ const pthread_barrierattr_t * attr,
+ unsigned int count);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier);
+
+/*
+ * Condition Variable Attribute Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr,
+ int *pshared);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr,
+ int pshared);
+
+/*
+ * Condition Variable Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond,
+ const pthread_condattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex,
+ const struct timespec *abstime);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond);
+
+/*
+ * Scheduling
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread,
+ int policy,
+ const struct sched_param *param);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread,
+ int *policy,
+ struct sched_param *param);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void);
+
+/*
+ * Read-Write Lock Functions
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock,
+ const pthread_rwlockattr_t *attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock,
+ const struct timespec *abstime);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock,
+ const struct timespec *abstime);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr,
+ int *pshared);
+
+PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr,
+ int pshared);
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1
+
+/*
+ * Signal Functions. Should be defined in <signal.h> but MSVC and MinGW32
+ * already have signal.h that don't define these.
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig);
+
+/*
+ * Non-portable functions
+ */
+
+/*
+ * Compatibility with Linux.
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr,
+ int kind);
+PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr,
+ int *kind);
+
+/*
+ * Possibly supported by other POSIX threads implementations
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval);
+PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void);
+PTW32_DLLPORT unsigned __int64 PTW32_CDECL pthread_getunique_np(pthread_t thread);
+
+/*
+ * Useful if an application wants to statically link
+ * the lib rather than load the DLL at run-time.
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void);
+PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void);
+PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void);
+PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void);
+
+/*
+ * Features that are auto-detected at load/run time.
+ */
+PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int);
+enum ptw32_features {
+ PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */
+ PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */
+};
+
+/*
+ * Register a system time change with the library.
+ * Causes the library to perform various functions
+ * in response to the change. Should be called whenever
+ * the application's top level window receives a
+ * WM_TIMECHANGE message. It can be passed directly to
+ * pthread_create() as a new thread if desired.
+ */
+PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *);
+
+#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+
+/*
+ * Returns the Win32 HANDLE for the POSIX thread.
+ */
+PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread);
+/*
+ * Returns the win32 thread ID for POSIX thread.
+ */
+PTW32_DLLPORT DWORD PTW32_CDECL pthread_getw32threadid_np (pthread_t thread);
+
+
+/*
+ * Protected Methods
+ *
+ * This function blocks until the given WIN32 handle
+ * is signaled or pthread_cancel had been called.
+ * This function allows the caller to hook into the
+ * PThreads cancel mechanism. It is implemented using
+ *
+ * WaitForMultipleObjects
+ *
+ * on 'waitHandle' and a manually reset WIN32 Event
+ * used to implement pthread_cancel. The 'timeout'
+ * argument to TimedWait is simply passed to
+ * WaitForMultipleObjects.
+ */
+PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle);
+PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle,
+ DWORD timeout);
+
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+/*
+ * Thread-Safe C Runtime Library Mappings.
+ */
+#if !defined(_UWIN)
+# if defined(NEED_ERRNO)
+ PTW32_DLLPORT int * PTW32_CDECL _errno( void );
+# else
+# if !defined(errno)
+# if (defined(_MT) || defined(_DLL))
+ __declspec(dllimport) extern int * __cdecl _errno(void);
+# define errno (*_errno())
+# endif
+# endif
+# endif
+#endif
+
+/*
+ * Some compiler environments don't define some things.
+ */
+#if defined(__BORLANDC__)
+# define _ftime ftime
+# define _timeb timeb
+#endif
+
+#if defined(__cplusplus)
+
+/*
+ * Internal exceptions
+ */
+class ptw32_exception {};
+class ptw32_exception_cancel : public ptw32_exception {};
+class ptw32_exception_exit : public ptw32_exception {};
+
+#endif
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+
+/* FIXME: This is only required if the library was built using SEH */
+/*
+ * Get internal SEH tag
+ */
+PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void);
+
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+#if !defined(PTW32_BUILD)
+
+#if defined(__CLEANUP_SEH)
+
+/*
+ * Redefine the SEH __except keyword to ensure that applications
+ * propagate our internal exceptions up to the library's internal handlers.
+ */
+#define __except( E ) \
+ __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \
+ ? EXCEPTION_CONTINUE_SEARCH : ( E ) )
+
+#endif /* __CLEANUP_SEH */
+
+#if defined(__CLEANUP_CXX)
+
+/*
+ * Redefine the C++ catch keyword to ensure that applications
+ * propagate our internal exceptions up to the library's internal handlers.
+ */
+#if defined(_MSC_VER)
+ /*
+ * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll'
+ * if you want Pthread-Win32 cancelation and pthread_exit to work.
+ */
+
+#if !defined(PtW32NoCatchWarn)
+
+#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.")
+#pragma message("------------------------------------------------------------------")
+#pragma message("When compiling applications with MSVC++ and C++ exception handling:")
+#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads")
+#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread")
+#pragma message(" cancelation and pthread_exit to work. For example:")
+#pragma message("")
+#pragma message(" #if defined(PtW32CatchAll)")
+#pragma message(" PtW32CatchAll")
+#pragma message(" #else")
+#pragma message(" catch(...)")
+#pragma message(" #endif")
+#pragma message(" {")
+#pragma message(" /* Catchall block processing */")
+#pragma message(" }")
+#pragma message("------------------------------------------------------------------")
+
+#endif
+
+#define PtW32CatchAll \
+ catch( ptw32_exception & ) { throw; } \
+ catch( ... )
+
+#else /* _MSC_VER */
+
+#define catch( E ) \
+ catch( ptw32_exception & ) { throw; } \
+ catch( E )
+
+#endif /* _MSC_VER */
+
+#endif /* __CLEANUP_CXX */
+
+#endif /* ! PTW32_BUILD */
+
+#if defined(__cplusplus)
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+#if defined(PTW32__HANDLE_DEF)
+# undef HANDLE
+#endif
+#if defined(PTW32__DWORD_DEF)
+# undef DWORD
+#endif
+
+#undef PTW32_LEVEL
+#undef PTW32_LEVEL_MAX
+
+#endif /* ! RC_INVOKED */
+
+#endif /* PTHREAD_H */
diff --git a/src/external/pthread/include/sched.h b/src/external/pthread/include/sched.h
new file mode 100644
index 00000000..f36a97a6
--- /dev/null
+++ b/src/external/pthread/include/sched.h
@@ -0,0 +1,183 @@
+/*
+ * Module: sched.h
+ *
+ * Purpose:
+ * Provides an implementation of POSIX realtime extensions
+ * as defined in
+ *
+ * POSIX 1003.1b-1993 (POSIX.1b)
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2005 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@callisto.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#if !defined(_SCHED_H)
+#define _SCHED_H
+
+#undef PTW32_SCHED_LEVEL
+
+#if defined(_POSIX_SOURCE)
+#define PTW32_SCHED_LEVEL 0
+/* Early POSIX */
+#endif
+
+#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
+#undef PTW32_SCHED_LEVEL
+#define PTW32_SCHED_LEVEL 1
+/* Include 1b, 1c and 1d */
+#endif
+
+#if defined(INCLUDE_NP)
+#undef PTW32_SCHED_LEVEL
+#define PTW32_SCHED_LEVEL 2
+/* Include Non-Portable extensions */
+#endif
+
+#define PTW32_SCHED_LEVEL_MAX 3
+
+#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_SCHED_LEVEL)
+#define PTW32_SCHED_LEVEL PTW32_SCHED_LEVEL_MAX
+/* Include everything */
+#endif
+
+
+#if defined(__GNUC__) && !defined(__declspec)
+# error Please upgrade your GNU compiler to one that supports __declspec.
+#endif
+
+/*
+ * When building the library, you should define PTW32_BUILD so that
+ * the variables/functions are exported correctly. When using the library,
+ * do NOT define PTW32_BUILD, and then the variables/functions will
+ * be imported correctly.
+ */
+#if !defined(PTW32_STATIC_LIB)
+# if defined(PTW32_BUILD)
+# define PTW32_DLLPORT __declspec (dllexport)
+# else
+# define PTW32_DLLPORT __declspec (dllimport)
+# endif
+#else
+# define PTW32_DLLPORT
+#endif
+
+/*
+ * This is a duplicate of what is in the autoconf config.h,
+ * which is only used when building the pthread-win32 libraries.
+ */
+
+#if !defined(PTW32_CONFIG_H)
+# if defined(WINCE)
+# define NEED_ERRNO
+# define NEED_SEM
+# endif
+# if defined(__MINGW64__)
+# define HAVE_STRUCT_TIMESPEC
+# define HAVE_MODE_T
+# elif defined(_UWIN) || defined(__MINGW32__)
+# define HAVE_MODE_T
+# endif
+#endif
+
+/*
+ *
+ */
+
+#if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX
+#if defined(NEED_ERRNO)
+#include "need_errno.h"
+#else
+#include <errno.h>
+#endif
+#endif /* PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX */
+
+#if (defined(__MINGW64__) || defined(__MINGW32__)) || defined(_UWIN)
+# if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX
+/* For pid_t */
+# include <sys/types.h>
+/* Required by Unix 98 */
+# include <time.h>
+# else
+ typedef int pid_t;
+# endif
+#else
+ typedef int pid_t;
+#endif
+
+/* Thread scheduling policies */
+
+enum {
+ SCHED_OTHER = 0,
+ SCHED_FIFO,
+ SCHED_RR,
+ SCHED_MIN = SCHED_OTHER,
+ SCHED_MAX = SCHED_RR
+};
+
+struct sched_param {
+ int sched_priority;
+};
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif /* __cplusplus */
+
+PTW32_DLLPORT int __cdecl sched_yield (void);
+
+PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy);
+
+PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy);
+
+PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy);
+
+PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid);
+
+/*
+ * Note that this macro returns ENOTSUP rather than
+ * ENOSYS as might be expected. However, returning ENOSYS
+ * should mean that sched_get_priority_{min,max} are
+ * not implemented as well as sched_rr_get_interval.
+ * This is not the case, since we just don't support
+ * round-robin scheduling. Therefore I have chosen to
+ * return the same value as sched_setscheduler when
+ * SCHED_RR is passed to it.
+ */
+#define sched_rr_get_interval(_pid, _interval) \
+ ( errno = ENOTSUP, (int) -1 )
+
+
+#if defined(__cplusplus)
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+#undef PTW32_SCHED_LEVEL
+#undef PTW32_SCHED_LEVEL_MAX
+
+#endif /* !_SCHED_H */
+
diff --git a/src/external/pthread/include/semaphore.h b/src/external/pthread/include/semaphore.h
new file mode 100644
index 00000000..c6e9407e
--- /dev/null
+++ b/src/external/pthread/include/semaphore.h
@@ -0,0 +1,169 @@
+/*
+ * Module: semaphore.h
+ *
+ * Purpose:
+ * Semaphores aren't actually part of the PThreads standard.
+ * They are defined by the POSIX Standard:
+ *
+ * POSIX 1003.1b-1993 (POSIX.1b)
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2005 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@callisto.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#if !defined( SEMAPHORE_H )
+#define SEMAPHORE_H
+
+#undef PTW32_SEMAPHORE_LEVEL
+
+#if defined(_POSIX_SOURCE)
+#define PTW32_SEMAPHORE_LEVEL 0
+/* Early POSIX */
+#endif
+
+#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
+#undef PTW32_SEMAPHORE_LEVEL
+#define PTW32_SEMAPHORE_LEVEL 1
+/* Include 1b, 1c and 1d */
+#endif
+
+#if defined(INCLUDE_NP)
+#undef PTW32_SEMAPHORE_LEVEL
+#define PTW32_SEMAPHORE_LEVEL 2
+/* Include Non-Portable extensions */
+#endif
+
+#define PTW32_SEMAPHORE_LEVEL_MAX 3
+
+#if !defined(PTW32_SEMAPHORE_LEVEL)
+#define PTW32_SEMAPHORE_LEVEL PTW32_SEMAPHORE_LEVEL_MAX
+/* Include everything */
+#endif
+
+#if defined(__GNUC__) && ! defined (__declspec)
+# error Please upgrade your GNU compiler to one that supports __declspec.
+#endif
+
+/*
+ * When building the library, you should define PTW32_BUILD so that
+ * the variables/functions are exported correctly. When using the library,
+ * do NOT define PTW32_BUILD, and then the variables/functions will
+ * be imported correctly.
+ */
+#if !defined(PTW32_STATIC_LIB)
+# if defined(PTW32_BUILD)
+# define PTW32_DLLPORT __declspec (dllexport)
+# else
+# define PTW32_DLLPORT __declspec (dllimport)
+# endif
+#else
+# define PTW32_DLLPORT
+#endif
+
+/*
+ * This is a duplicate of what is in the autoconf config.h,
+ * which is only used when building the pthread-win32 libraries.
+ */
+
+#if !defined(PTW32_CONFIG_H)
+# if defined(WINCE)
+# define NEED_ERRNO
+# define NEED_SEM
+# endif
+# if defined(__MINGW64__)
+# define HAVE_STRUCT_TIMESPEC
+# define HAVE_MODE_T
+# elif defined(_UWIN) || defined(__MINGW32__)
+# define HAVE_MODE_T
+# endif
+#endif
+
+/*
+ *
+ */
+
+#if PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX
+#if defined(NEED_ERRNO)
+#include "need_errno.h"
+#else
+#include <errno.h>
+#endif
+#endif /* PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX */
+
+#define _POSIX_SEMAPHORES
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif /* __cplusplus */
+
+#if !defined(HAVE_MODE_T)
+typedef unsigned int mode_t;
+#endif
+
+
+typedef struct sem_t_ * sem_t;
+
+PTW32_DLLPORT int __cdecl sem_init (sem_t * sem,
+ int pshared,
+ unsigned int value);
+
+PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem);
+
+PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem);
+
+PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem);
+
+PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem,
+ const struct timespec * abstime);
+
+PTW32_DLLPORT int __cdecl sem_post (sem_t * sem);
+
+PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem,
+ int count);
+
+PTW32_DLLPORT int __cdecl sem_open (const char * name,
+ int oflag,
+ mode_t mode,
+ unsigned int value);
+
+PTW32_DLLPORT int __cdecl sem_close (sem_t * sem);
+
+PTW32_DLLPORT int __cdecl sem_unlink (const char * name);
+
+PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem,
+ int * sval);
+
+#if defined(__cplusplus)
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+#undef PTW32_SEMAPHORE_LEVEL
+#undef PTW32_SEMAPHORE_LEVEL_MAX
+
+#endif /* !SEMAPHORE_H */
diff --git a/src/external/pthread/lib/libpthreadGC2.a b/src/external/pthread/lib/libpthreadGC2.a
new file mode 100644
index 00000000..df211759
--- /dev/null
+++ b/src/external/pthread/lib/libpthreadGC2.a
Binary files differ
diff --git a/src/external/pthread/lib/pthreadGC2.dll b/src/external/pthread/lib/pthreadGC2.dll
new file mode 100644
index 00000000..67b9289d
--- /dev/null
+++ b/src/external/pthread/lib/pthreadGC2.dll
Binary files differ
diff --git a/src/external/stb_image.h b/src/external/stb_image.h
new file mode 100644
index 00000000..4d8d0133
--- /dev/null
+++ b/src/external/stb_image.h
@@ -0,0 +1,7110 @@
+/* stb_image - v2.14 - public domain image loader - http://nothings.org/stb_image.h
+ no warranty implied; use at your own risk
+
+ Do this:
+ #define STB_IMAGE_IMPLEMENTATION
+ before you include this file in *one* C or C++ file to create the implementation.
+
+ // i.e. it should look like this:
+ #include ...
+ #include ...
+ #include ...
+ #define STB_IMAGE_IMPLEMENTATION
+ #include "stb_image.h"
+
+ You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
+ And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
+
+
+ QUICK NOTES:
+ Primarily of interest to game developers and other people who can
+ avoid problematic images and only need the trivial interface
+
+ JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
+ PNG 1/2/4/8-bit-per-channel (16 bpc not supported)
+
+ TGA (not sure what subset, if a subset)
+ BMP non-1bpp, non-RLE
+ PSD (composited view only, no extra channels, 8/16 bit-per-channel)
+
+ GIF (*comp always reports as 4-channel)
+ HDR (radiance rgbE format)
+ PIC (Softimage PIC)
+ PNM (PPM and PGM binary only)
+
+ Animated GIF still needs a proper API, but here's one way to do it:
+ http://gist.github.com/urraka/685d9a6340b26b830d49
+
+ - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
+ - decode from arbitrary I/O callbacks
+ - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
+
+ Full documentation under "DOCUMENTATION" below.
+
+
+ Revision 2.00 release notes:
+
+ - Progressive JPEG is now supported.
+
+ - PPM and PGM binary formats are now supported, thanks to Ken Miller.
+
+ - x86 platforms now make use of SSE2 SIMD instructions for
+ JPEG decoding, and ARM platforms can use NEON SIMD if requested.
+ This work was done by Fabian "ryg" Giesen. SSE2 is used by
+ default, but NEON must be enabled explicitly; see docs.
+
+ With other JPEG optimizations included in this version, we see
+ 2x speedup on a JPEG on an x86 machine, and a 1.5x speedup
+ on a JPEG on an ARM machine, relative to previous versions of this
+ library. The same results will not obtain for all JPGs and for all
+ x86/ARM machines. (Note that progressive JPEGs are significantly
+ slower to decode than regular JPEGs.) This doesn't mean that this
+ is the fastest JPEG decoder in the land; rather, it brings it
+ closer to parity with standard libraries. If you want the fastest
+ decode, look elsewhere. (See "Philosophy" section of docs below.)
+
+ See final bullet items below for more info on SIMD.
+
+ - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing
+ the memory allocator. Unlike other STBI libraries, these macros don't
+ support a context parameter, so if you need to pass a context in to
+ the allocator, you'll have to store it in a global or a thread-local
+ variable.
+
+ - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and
+ STBI_NO_LINEAR.
+ STBI_NO_HDR: suppress implementation of .hdr reader format
+ STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API
+
+ - You can suppress implementation of any of the decoders to reduce
+ your code footprint by #defining one or more of the following
+ symbols before creating the implementation.
+
+ STBI_NO_JPEG
+ STBI_NO_PNG
+ STBI_NO_BMP
+ STBI_NO_PSD
+ STBI_NO_TGA
+ STBI_NO_GIF
+ STBI_NO_HDR
+ STBI_NO_PIC
+ STBI_NO_PNM (.ppm and .pgm)
+
+ - You can request *only* certain decoders and suppress all other ones
+ (this will be more forward-compatible, as addition of new decoders
+ doesn't require you to disable them explicitly):
+
+ STBI_ONLY_JPEG
+ STBI_ONLY_PNG
+ STBI_ONLY_BMP
+ STBI_ONLY_PSD
+ STBI_ONLY_TGA
+ STBI_ONLY_GIF
+ STBI_ONLY_HDR
+ STBI_ONLY_PIC
+ STBI_ONLY_PNM (.ppm and .pgm)
+
+ Note that you can define multiples of these, and you will get all
+ of them ("only x" and "only y" is interpreted to mean "only x&y").
+
+ - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
+ want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
+
+ - Compilation of all SIMD code can be suppressed with
+ #define STBI_NO_SIMD
+ It should not be necessary to disable SIMD unless you have issues
+ compiling (e.g. using an x86 compiler which doesn't support SSE
+ intrinsics or that doesn't support the method used to detect
+ SSE2 support at run-time), and even those can be reported as
+ bugs so I can refine the built-in compile-time checking to be
+ smarter.
+
+ - The old STBI_SIMD system which allowed installing a user-defined
+ IDCT etc. has been removed. If you need this, don't upgrade. My
+ assumption is that almost nobody was doing this, and those who
+ were will find the built-in SIMD more satisfactory anyway.
+
+ - RGB values computed for JPEG images are slightly different from
+ previous versions of stb_image. (This is due to using less
+ integer precision in SIMD.) The C code has been adjusted so
+ that the same RGB values will be computed regardless of whether
+ SIMD support is available, so your app should always produce
+ consistent results. But these results are slightly different from
+ previous versions. (Specifically, about 3% of available YCbCr values
+ will compute different RGB results from pre-1.49 versions by +-1;
+ most of the deviating values are one smaller in the G channel.)
+
+ - If you must produce consistent results with previous versions of
+ stb_image, #define STBI_JPEG_OLD and you will get the same results
+ you used to; however, you will not get the SIMD speedups for
+ the YCbCr-to-RGB conversion step (although you should still see
+ significant JPEG speedup from the other changes).
+
+ Please note that STBI_JPEG_OLD is a temporary feature; it will be
+ removed in future versions of the library. It is only intended for
+ near-term back-compatibility use.
+
+
+ Latest revision history:
+ 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
+ 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+ 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
+ RGB-format JPEG; remove white matting in PSD;
+ allocate large structures on the stack;
+ correct channel count for PNG & BMP
+ 2.10 (2016-01-22) avoid warning introduced in 2.09
+ 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
+ 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
+ 2.07 (2015-09-13) partial animated GIF support
+ limited 16-bit PSD support
+ minor bugs, code cleanup, and compiler warnings
+
+ See end of file for full revision history.
+
+
+ ============================ Contributors =========================
+
+ Image formats Extensions, features
+ Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info)
+ Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info)
+ Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG)
+ Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks)
+ Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG)
+ Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
+ Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
+ github:urraka (animated gif) Junggon Kim (PNM comments)
+ Daniel Gibson (16-bit TGA)
+ socks-the-fox (16-bit TGA)
+ Optimizations & bugfixes
+ Fabian "ryg" Giesen
+ Arseny Kapoulkine
+
+ Bug & warning fixes
+ Marc LeBlanc David Woo Guillaume George Martins Mozeiko
+ Christpher Lloyd Martin Golini Jerry Jansson Joseph Thomson
+ Dave Moore Roy Eltham Hayaki Saito Phil Jordan
+ Won Chun Luke Graham Johan Duparc Nathan Reed
+ the Horde3D community Thomas Ruf Ronny Chevalier Nick Verigakis
+ Janez Zemva John Bartholomew Michal Cichon github:svdijk
+ Jonathan Blow Ken Hamada Tero Hanninen Baldur Karlsson
+ Laurent Gomila Cort Stratton Sergio Gonzalez github:romigrou
+ Aruelien Pocheville Thibault Reuille Cass Everitt Matthew Gregan
+ Ryamond Barbiero Paul Du Bois Engin Manap github:snagar
+ Michaelangel007@github Oriol Ferrer Mesia Dale Weiler github:Zelex
+ Philipp Wiesemann Josh Tobin github:rlyeh github:grim210@github
+ Blazej Dariusz Roszkowski github:sammyhw
+
+
+LICENSE
+
+This software is dual-licensed to the public domain and under the following
+license: you are granted a perpetual, irrevocable license to copy, modify,
+publish, and distribute this file as you see fit.
+
+*/
+
+#ifndef STBI_INCLUDE_STB_IMAGE_H
+#define STBI_INCLUDE_STB_IMAGE_H
+
+// DOCUMENTATION
+//
+// Limitations:
+// - no 16-bit-per-channel PNG
+// - no 12-bit-per-channel JPEG
+// - no JPEGs with arithmetic coding
+// - no 1-bit BMP
+// - GIF always returns *comp=4
+//
+// Basic usage (see HDR discussion below for HDR usage):
+// int x,y,n;
+// unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+// // ... process data if not NULL ...
+// // ... x = width, y = height, n = # 8-bit components per pixel ...
+// // ... replace '0' with '1'..'4' to force that many components per pixel
+// // ... but 'n' will always be the number that it would have been if you said 0
+// stbi_image_free(data)
+//
+// Standard parameters:
+// int *x -- outputs image width in pixels
+// int *y -- outputs image height in pixels
+// int *channels_in_file -- outputs # of image components in image file
+// int desired_channels -- if non-zero, # of image components requested in result
+//
+// The return value from an image loader is an 'unsigned char *' which points
+// to the pixel data, or NULL on an allocation failure or if the image is
+// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
+// with each pixel consisting of N interleaved 8-bit components; the first
+// pixel pointed to is top-left-most in the image. There is no padding between
+// image scanlines or between pixels, regardless of format. The number of
+// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.
+// If req_comp is non-zero, *comp has the number of components that _would_
+// have been output otherwise. E.g. if you set req_comp to 4, you will always
+// get RGBA output, but you can check *comp to see if it's trivially opaque
+// because e.g. there were only 3 channels in the source image.
+//
+// An output image with N components has the following components interleaved
+// in this order in each pixel:
+//
+// N=#comp components
+// 1 grey
+// 2 grey, alpha
+// 3 red, green, blue
+// 4 red, green, blue, alpha
+//
+// If image loading fails for any reason, the return value will be NULL,
+// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()
+// can be queried for an extremely brief, end-user unfriendly explanation
+// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid
+// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
+// more user-friendly ones.
+//
+// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
+//
+// ===========================================================================
+//
+// Philosophy
+//
+// stb libraries are designed with the following priorities:
+//
+// 1. easy to use
+// 2. easy to maintain
+// 3. good performance
+//
+// Sometimes I let "good performance" creep up in priority over "easy to maintain",
+// and for best performance I may provide less-easy-to-use APIs that give higher
+// performance, in addition to the easy to use ones. Nevertheless, it's important
+// to keep in mind that from the standpoint of you, a client of this library,
+// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all.
+//
+// Some secondary priorities arise directly from the first two, some of which
+// make more explicit reasons why performance can't be emphasized.
+//
+// - Portable ("ease of use")
+// - Small footprint ("easy to maintain")
+// - No dependencies ("ease of use")
+//
+// ===========================================================================
+//
+// I/O callbacks
+//
+// I/O callbacks allow you to read from arbitrary sources, like packaged
+// files or some other source. Data read from callbacks are processed
+// through a small internal buffer (currently 128 bytes) to try to reduce
+// overhead.
+//
+// The three functions you must define are "read" (reads some bytes of data),
+// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
+//
+// ===========================================================================
+//
+// SIMD support
+//
+// The JPEG decoder will try to automatically use SIMD kernels on x86 when
+// supported by the compiler. For ARM Neon support, you must explicitly
+// request it.
+//
+// (The old do-it-yourself SIMD API is no longer supported in the current
+// code.)
+//
+// On x86, SSE2 will automatically be used when available based on a run-time
+// test; if not, the generic C versions are used as a fall-back. On ARM targets,
+// the typical path is to have separate builds for NEON and non-NEON devices
+// (at least this is true for iOS and Android). Therefore, the NEON support is
+// toggled by a build flag: define STBI_NEON to get NEON loops.
+//
+// The output of the JPEG decoder is slightly different from versions where
+// SIMD support was introduced (that is, for versions before 1.49). The
+// difference is only +-1 in the 8-bit RGB channels, and only on a small
+// fraction of pixels. You can force the pre-1.49 behavior by defining
+// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path
+// and hence cost some performance.
+//
+// If for some reason you do not want to use any of SIMD code, or if
+// you have issues compiling it, you can disable it entirely by
+// defining STBI_NO_SIMD.
+//
+// ===========================================================================
+//
+// HDR image support (disable by defining STBI_NO_HDR)
+//
+// stb_image now supports loading HDR images in general, and currently
+// the Radiance .HDR file format, although the support is provided
+// generically. You can still load any file through the existing interface;
+// if you attempt to load an HDR file, it will be automatically remapped to
+// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
+// both of these constants can be reconfigured through this interface:
+//
+// stbi_hdr_to_ldr_gamma(2.2f);
+// stbi_hdr_to_ldr_scale(1.0f);
+//
+// (note, do not use _inverse_ constants; stbi_image will invert them
+// appropriately).
+//
+// Additionally, there is a new, parallel interface for loading files as
+// (linear) floats to preserve the full dynamic range:
+//
+// float *data = stbi_loadf(filename, &x, &y, &n, 0);
+//
+// If you load LDR images through this interface, those images will
+// be promoted to floating point values, run through the inverse of
+// constants corresponding to the above:
+//
+// stbi_ldr_to_hdr_scale(1.0f);
+// stbi_ldr_to_hdr_gamma(2.2f);
+//
+// Finally, given a filename (or an open file or memory block--see header
+// file for details) containing image data, you can query for the "most
+// appropriate" interface to use (that is, whether the image is HDR or
+// not), using:
+//
+// stbi_is_hdr(char *filename);
+//
+// ===========================================================================
+//
+// iPhone PNG support:
+//
+// By default we convert iphone-formatted PNGs back to RGB, even though
+// they are internally encoded differently. You can disable this conversion
+// by by calling stbi_convert_iphone_png_to_rgb(0), in which case
+// you will always just get the native iphone "format" through (which
+// is BGR stored in RGB).
+//
+// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
+// pixel to remove any premultiplied alpha *only* if the image file explicitly
+// says there's premultiplied data (currently only happens in iPhone images,
+// and only if iPhone convert-to-rgb processing is on).
+//
+
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif // STBI_NO_STDIO
+
+#define STBI_NO_HDR // RaySan: not required by raylib
+//#define STBI_NO_SIMD // RaySan: issues when compiling with GCC 4.7.2
+
+// NOTE: Added to work with raylib on Android
+#if defined(PLATFORM_ANDROID)
+ #include "utils.h" // RaySan: Android fopen function map
+#endif
+
+#define STBI_VERSION 1
+
+enum
+{
+ STBI_default = 0, // only used for req_comp
+
+ STBI_grey = 1,
+ STBI_grey_alpha = 2,
+ STBI_rgb = 3,
+ STBI_rgb_alpha = 4
+};
+
+typedef unsigned char stbi_uc;
+typedef unsigned short stbi_us;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef STB_IMAGE_STATIC
+#define STBIDEF static
+#else
+#define STBIDEF extern
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PRIMARY API - works on images of any type
+//
+
+//
+// load image by filename, open file, or memory buffer
+//
+
+typedef struct
+{
+ int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read
+ void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
+ int (*eof) (void *user); // returns nonzero if we are at end of file/data
+} stbi_io_callbacks;
+
+////////////////////////////////////
+//
+// 8-bits-per-channel interface
+//
+
+STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+// for stbi_load_from_file, file pointer is left pointing immediately after image
+#endif
+
+////////////////////////////////////
+//
+// 16-bits-per-channel interface
+//
+
+STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+#endif
+// @TODO the other variants
+
+////////////////////////////////////
+//
+// float-per-channel interface
+//
+#ifndef STBI_NO_LINEAR
+ STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+ STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+ STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+ #ifndef STBI_NO_STDIO
+ STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+ #endif
+#endif
+
+#ifndef STBI_NO_HDR
+ STBIDEF void stbi_hdr_to_ldr_gamma(float gamma);
+ STBIDEF void stbi_hdr_to_ldr_scale(float scale);
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_LINEAR
+ STBIDEF void stbi_ldr_to_hdr_gamma(float gamma);
+ STBIDEF void stbi_ldr_to_hdr_scale(float scale);
+#endif // STBI_NO_LINEAR
+
+// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
+STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_is_hdr (char const *filename);
+STBIDEF int stbi_is_hdr_from_file(FILE *f);
+#endif // STBI_NO_STDIO
+
+
+// get a VERY brief reason for failure
+// NOT THREADSAFE
+STBIDEF const char *stbi_failure_reason (void);
+
+// free the loaded image -- this is just free()
+STBIDEF void stbi_image_free (void *retval_from_stbi_load);
+
+// get image dimensions & components without fully decoding
+STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
+STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp);
+STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
+
+#endif
+
+
+
+// for image formats that explicitly notate that they have premultiplied alpha,
+// we just return the colors as stored in the file. set this flag to force
+// unpremultiplication. results are undefined if the unpremultiply overflow.
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
+
+// indicate whether we should process iphone images back to canonical format,
+// or just pass them through "as-is"
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
+
+// flip the image vertically, so the first pixel in the output array is the bottom left
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
+
+// ZLIB client - used by PNG, available for other purposes
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
+STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+//
+//// end header file /////////////////////////////////////////////////////
+#endif // STBI_INCLUDE_STB_IMAGE_H
+
+#ifdef STB_IMAGE_IMPLEMENTATION
+
+#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \
+ || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \
+ || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \
+ || defined(STBI_ONLY_ZLIB)
+ #ifndef STBI_ONLY_JPEG
+ #define STBI_NO_JPEG
+ #endif
+ #ifndef STBI_ONLY_PNG
+ #define STBI_NO_PNG
+ #endif
+ #ifndef STBI_ONLY_BMP
+ #define STBI_NO_BMP
+ #endif
+ #ifndef STBI_ONLY_PSD
+ #define STBI_NO_PSD
+ #endif
+ #ifndef STBI_ONLY_TGA
+ #define STBI_NO_TGA
+ #endif
+ #ifndef STBI_ONLY_GIF
+ #define STBI_NO_GIF
+ #endif
+ #ifndef STBI_ONLY_HDR
+ #define STBI_NO_HDR
+ #endif
+ #ifndef STBI_ONLY_PIC
+ #define STBI_NO_PIC
+ #endif
+ #ifndef STBI_ONLY_PNM
+ #define STBI_NO_PNM
+ #endif
+#endif
+
+#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)
+#define STBI_NO_ZLIB
+#endif
+
+
+#include <stdarg.h>
+#include <stddef.h> // ptrdiff_t on osx
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+#include <math.h> // ldexp
+#endif
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif
+
+#ifndef STBI_ASSERT
+#include <assert.h>
+#define STBI_ASSERT(x) assert(x)
+#endif
+
+
+#ifndef _MSC_VER
+ #ifdef __cplusplus
+ #define stbi_inline inline
+ #else
+ #define stbi_inline
+ #endif
+#else
+ #define stbi_inline __forceinline
+#endif
+
+
+#ifdef _MSC_VER
+typedef unsigned short stbi__uint16;
+typedef signed short stbi__int16;
+typedef unsigned int stbi__uint32;
+typedef signed int stbi__int32;
+#else
+#include <stdint.h>
+typedef uint16_t stbi__uint16;
+typedef int16_t stbi__int16;
+typedef uint32_t stbi__uint32;
+typedef int32_t stbi__int32;
+#endif
+
+// should produce compiler error if size is wrong
+typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
+
+#ifdef _MSC_VER
+#define STBI_NOTUSED(v) (void)(v)
+#else
+#define STBI_NOTUSED(v) (void)sizeof(v)
+#endif
+
+#ifdef _MSC_VER
+#define STBI_HAS_LROTL
+#endif
+
+#ifdef STBI_HAS_LROTL
+ #define stbi_lrot(x,y) _lrotl(x,y)
+#else
+ #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y))))
+#endif
+
+#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
+// ok
+#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)
+// ok
+#else
+#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)."
+#endif
+
+#ifndef STBI_MALLOC
+#define STBI_MALLOC(sz) malloc(sz)
+#define STBI_REALLOC(p,newsz) realloc(p,newsz)
+#define STBI_FREE(p) free(p)
+#endif
+
+#ifndef STBI_REALLOC_SIZED
+#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
+#endif
+
+// x86/x64 detection
+#if defined(__x86_64__) || defined(_M_X64)
+#define STBI__X64_TARGET
+#elif defined(__i386) || defined(_M_IX86)
+#define STBI__X86_TARGET
+#endif
+
+#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
+// NOTE: not clear do we actually need this for the 64-bit path?
+// gcc doesn't support sse2 intrinsics unless you compile with -msse2,
+// (but compiling with -msse2 allows the compiler to use SSE2 everywhere;
+// this is just broken and gcc are jerks for not fixing it properly
+// http://www.virtualdub.org/blog/pivot/entry.php?id=363 )
+#define STBI_NO_SIMD
+#endif
+
+#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
+// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
+//
+// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
+// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
+// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
+// simultaneously enabling "-mstackrealign".
+//
+// See https://github.com/nothings/stb/issues/81 for more information.
+//
+// So default to no SSE2 on 32-bit MinGW. If you've read this far and added
+// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.
+#define STBI_NO_SIMD
+#endif
+
+#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))
+#define STBI_SSE2
+#include <emmintrin.h>
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1400 // not VC6
+#include <intrin.h> // __cpuid
+static int stbi__cpuid3(void)
+{
+ int info[4];
+ __cpuid(info,1);
+ return info[3];
+}
+#else
+static int stbi__cpuid3(void)
+{
+ int res;
+ __asm {
+ mov eax,1
+ cpuid
+ mov res,edx
+ }
+ return res;
+}
+#endif
+
+#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
+
+static int stbi__sse2_available()
+{
+ int info3 = stbi__cpuid3();
+ return ((info3 >> 26) & 1) != 0;
+}
+#else // assume GCC-style if not VC++
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+
+static int stbi__sse2_available()
+{
+#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later
+ // GCC 4.8+ has a nice way to do this
+ return __builtin_cpu_supports("sse2");
+#else
+ // portable way to do this, preferably without using GCC inline ASM?
+ // just bail for now.
+ return 0;
+#endif
+}
+#endif
+#endif
+
+// ARM NEON
+#if defined(STBI_NO_SIMD) && defined(STBI_NEON)
+#undef STBI_NEON
+#endif
+
+#ifdef STBI_NEON
+#include <arm_neon.h>
+// assume GCC or Clang on ARM targets
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+#endif
+
+#ifndef STBI_SIMD_ALIGN
+#define STBI_SIMD_ALIGN(type, name) type name
+#endif
+
+///////////////////////////////////////////////
+//
+// stbi__context struct and start_xxx functions
+
+// stbi__context structure is our basic context used by all images, so it
+// contains all the IO context, plus some basic image information
+typedef struct
+{
+ stbi__uint32 img_x, img_y;
+ int img_n, img_out_n;
+
+ stbi_io_callbacks io;
+ void *io_user_data;
+
+ int read_from_callbacks;
+ int buflen;
+ stbi_uc buffer_start[128];
+
+ stbi_uc *img_buffer, *img_buffer_end;
+ stbi_uc *img_buffer_original, *img_buffer_original_end;
+} stbi__context;
+
+
+static void stbi__refill_buffer(stbi__context *s);
+
+// initialize a memory-decode context
+static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
+{
+ s->io.read = NULL;
+ s->read_from_callbacks = 0;
+ s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;
+ s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;
+}
+
+// initialize a callback-based context
+static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
+{
+ s->io = *c;
+ s->io_user_data = user;
+ s->buflen = sizeof(s->buffer_start);
+ s->read_from_callbacks = 1;
+ s->img_buffer_original = s->buffer_start;
+ stbi__refill_buffer(s);
+ s->img_buffer_original_end = s->img_buffer_end;
+}
+
+#ifndef STBI_NO_STDIO
+
+static int stbi__stdio_read(void *user, char *data, int size)
+{
+ return (int) fread(data,1,size,(FILE*) user);
+}
+
+static void stbi__stdio_skip(void *user, int n)
+{
+ fseek((FILE*) user, n, SEEK_CUR);
+}
+
+static int stbi__stdio_eof(void *user)
+{
+ return feof((FILE*) user);
+}
+
+static stbi_io_callbacks stbi__stdio_callbacks =
+{
+ stbi__stdio_read,
+ stbi__stdio_skip,
+ stbi__stdio_eof,
+};
+
+static void stbi__start_file(stbi__context *s, FILE *f)
+{
+ stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);
+}
+
+//static void stop_file(stbi__context *s) { }
+
+#endif // !STBI_NO_STDIO
+
+static void stbi__rewind(stbi__context *s)
+{
+ // conceptually rewind SHOULD rewind to the beginning of the stream,
+ // but we just rewind to the beginning of the initial buffer, because
+ // we only use it after doing 'test', which only ever looks at at most 92 bytes
+ s->img_buffer = s->img_buffer_original;
+ s->img_buffer_end = s->img_buffer_original_end;
+}
+
+enum
+{
+ STBI_ORDER_RGB,
+ STBI_ORDER_BGR
+};
+
+typedef struct
+{
+ int bits_per_channel;
+ int num_channels;
+ int channel_order;
+} stbi__result_info;
+
+#ifndef STBI_NO_JPEG
+static int stbi__jpeg_test(stbi__context *s);
+static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNG
+static int stbi__png_test(stbi__context *s);
+static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_test(stbi__context *s);
+static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_TGA
+static int stbi__tga_test(stbi__context *s);
+static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_test(stbi__context *s);
+static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);
+static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static int stbi__hdr_test(stbi__context *s);
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_test(stbi__context *s);
+static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_GIF
+static int stbi__gif_test(stbi__context *s);
+static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNM
+static int stbi__pnm_test(stbi__context *s);
+static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+// this is not threadsafe
+static const char *stbi__g_failure_reason;
+
+STBIDEF const char *stbi_failure_reason(void)
+{
+ return stbi__g_failure_reason;
+}
+
+static int stbi__err(const char *str)
+{
+ stbi__g_failure_reason = str;
+ return 0;
+}
+
+static void *stbi__malloc(size_t size)
+{
+ return STBI_MALLOC(size);
+}
+
+// stb_image uses ints pervasively, including for offset calculations.
+// therefore the largest decoded image size we can support with the
+// current code, even on 64-bit targets, is INT_MAX. this is not a
+// significant limitation for the intended use case.
+//
+// we do, however, need to make sure our size calculations don't
+// overflow. hence a few helper functions for size calculations that
+// multiply integers together, making sure that they're non-negative
+// and no overflow occurs.
+
+// return 1 if the sum is valid, 0 on overflow.
+// negative terms are considered invalid.
+static int stbi__addsizes_valid(int a, int b)
+{
+ if (b < 0) return 0;
+ // now 0 <= b <= INT_MAX, hence also
+ // 0 <= INT_MAX - b <= INTMAX.
+ // And "a + b <= INT_MAX" (which might overflow) is the
+ // same as a <= INT_MAX - b (no overflow)
+ return a <= INT_MAX - b;
+}
+
+// returns 1 if the product is valid, 0 on overflow.
+// negative factors are considered invalid.
+static int stbi__mul2sizes_valid(int a, int b)
+{
+ if (a < 0 || b < 0) return 0;
+ if (b == 0) return 1; // mul-by-0 is always safe
+ // portable way to check for no overflows in a*b
+ return a <= INT_MAX/b;
+}
+
+// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad2sizes_valid(int a, int b, int add)
+{
+ return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
+}
+
+// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad3sizes_valid(int a, int b, int c, int add)
+{
+ return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
+ stbi__addsizes_valid(a*b*c, add);
+}
+
+// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
+{
+ return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
+ stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
+}
+
+// mallocs with size overflow checking
+static void *stbi__malloc_mad2(int a, int b, int add)
+{
+ if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
+ return stbi__malloc(a*b + add);
+}
+
+static void *stbi__malloc_mad3(int a, int b, int c, int add)
+{
+ if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;
+ return stbi__malloc(a*b*c + add);
+}
+
+static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
+{
+ if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
+ return stbi__malloc(a*b*c*d + add);
+}
+
+// stbi__err - error
+// stbi__errpf - error returning pointer to float
+// stbi__errpuc - error returning pointer to unsigned char
+
+#ifdef STBI_NO_FAILURE_STRINGS
+ #define stbi__err(x,y) 0
+#elif defined(STBI_FAILURE_USERMSG)
+ #define stbi__err(x,y) stbi__err(y)
+#else
+ #define stbi__err(x,y) stbi__err(x)
+#endif
+
+#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))
+#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))
+
+STBIDEF void stbi_image_free(void *retval_from_stbi_load)
+{
+ STBI_FREE(retval_from_stbi_load);
+}
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp);
+#endif
+
+static int stbi__vertically_flip_on_load = 0;
+
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
+{
+ stbi__vertically_flip_on_load = flag_true_if_should_flip;
+}
+
+static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
+{
+ memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields
+ ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed
+ ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order
+ ri->num_channels = 0;
+
+ #ifndef STBI_NO_JPEG
+ if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_PNG
+ if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_BMP
+ if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_GIF
+ if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_PSD
+ if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);
+ #endif
+ #ifndef STBI_NO_PIC
+ if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_PNM
+ if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri);
+ #endif
+
+ #ifndef STBI_NO_HDR
+ if (stbi__hdr_test(s)) {
+ float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri);
+ return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
+ }
+ #endif
+
+ #ifndef STBI_NO_TGA
+ // test tga last because it's a crappy test!
+ if (stbi__tga_test(s))
+ return stbi__tga_load(s,x,y,comp,req_comp, ri);
+ #endif
+
+ return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
+}
+
+static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels)
+{
+ int i;
+ int img_len = w * h * channels;
+ stbi_uc *reduced;
+
+ reduced = (stbi_uc *) stbi__malloc(img_len);
+ if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory");
+
+ for (i = 0; i < img_len; ++i)
+ reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling
+
+ STBI_FREE(orig);
+ return reduced;
+}
+
+static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels)
+{
+ int i;
+ int img_len = w * h * channels;
+ stbi__uint16 *enlarged;
+
+ enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);
+ if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
+
+ for (i = 0; i < img_len; ++i)
+ enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff
+
+ STBI_FREE(orig);
+ return enlarged;
+}
+
+static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__result_info ri;
+ void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);
+
+ if (result == NULL)
+ return NULL;
+
+ if (ri.bits_per_channel != 8) {
+ STBI_ASSERT(ri.bits_per_channel == 16);
+ result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
+ ri.bits_per_channel = 8;
+ }
+
+ // @TODO: move stbi__convert_format to here
+
+ if (stbi__vertically_flip_on_load) {
+ int w = *x, h = *y;
+ int channels = req_comp ? req_comp : *comp;
+ int row,col,z;
+ stbi_uc *image = (stbi_uc *) result;
+
+ // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
+ for (row = 0; row < (h>>1); row++) {
+ for (col = 0; col < w; col++) {
+ for (z = 0; z < channels; z++) {
+ stbi_uc temp = image[(row * w + col) * channels + z];
+ image[(row * w + col) * channels + z] = image[((h - row - 1) * w + col) * channels + z];
+ image[((h - row - 1) * w + col) * channels + z] = temp;
+ }
+ }
+ }
+ }
+
+ return (unsigned char *) result;
+}
+
+static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__result_info ri;
+ void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);
+
+ if (result == NULL)
+ return NULL;
+
+ if (ri.bits_per_channel != 16) {
+ STBI_ASSERT(ri.bits_per_channel == 8);
+ result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
+ ri.bits_per_channel = 16;
+ }
+
+ // @TODO: move stbi__convert_format16 to here
+ // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision
+
+ if (stbi__vertically_flip_on_load) {
+ int w = *x, h = *y;
+ int channels = req_comp ? req_comp : *comp;
+ int row,col,z;
+ stbi__uint16 *image = (stbi__uint16 *) result;
+
+ // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
+ for (row = 0; row < (h>>1); row++) {
+ for (col = 0; col < w; col++) {
+ for (z = 0; z < channels; z++) {
+ stbi__uint16 temp = image[(row * w + col) * channels + z];
+ image[(row * w + col) * channels + z] = image[((h - row - 1) * w + col) * channels + z];
+ image[((h - row - 1) * w + col) * channels + z] = temp;
+ }
+ }
+ }
+ }
+
+ return (stbi__uint16 *) result;
+}
+
+#ifndef STBI_NO_HDR
+static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
+{
+ if (stbi__vertically_flip_on_load && result != NULL) {
+ int w = *x, h = *y;
+ int depth = req_comp ? req_comp : *comp;
+ int row,col,z;
+ float temp;
+
+ // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
+ for (row = 0; row < (h>>1); row++) {
+ for (col = 0; col < w; col++) {
+ for (z = 0; z < depth; z++) {
+ temp = result[(row * w + col) * depth + z];
+ result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];
+ result[((h - row - 1) * w + col) * depth + z] = temp;
+ }
+ }
+ }
+ }
+}
+#endif
+
+#ifndef STBI_NO_STDIO
+
+static FILE *stbi__fopen(char const *filename, char const *mode)
+{
+ FILE *f;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ if (0 != fopen_s(&f, filename, mode))
+ f=0;
+#else
+ f = fopen(filename, mode);
+#endif
+ return f;
+}
+
+
+STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ unsigned char *result;
+ if (!f) return stbi__errpuc("can't fopen", "Unable to open file");
+ result = stbi_load_from_file(f,x,y,comp,req_comp);
+ fclose(f);
+ return result;
+}
+
+STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ unsigned char *result;
+ stbi__context s;
+ stbi__start_file(&s,f);
+ result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+ if (result) {
+ // need to 'unget' all the characters in the IO buffer
+ fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+ }
+ return result;
+}
+
+STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__uint16 *result;
+ stbi__context s;
+ stbi__start_file(&s,f);
+ result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);
+ if (result) {
+ // need to 'unget' all the characters in the IO buffer
+ fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+ }
+ return result;
+}
+
+STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ stbi__uint16 *result;
+ if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file");
+ result = stbi_load_from_file_16(f,x,y,comp,req_comp);
+ fclose(f);
+ return result;
+}
+
+
+#endif //!STBI_NO_STDIO
+
+STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+}
+
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+ return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ unsigned char *data;
+ #ifndef STBI_NO_HDR
+ if (stbi__hdr_test(s)) {
+ stbi__result_info ri;
+ float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri);
+ if (hdr_data)
+ stbi__float_postprocess(hdr_data,x,y,comp,req_comp);
+ return hdr_data;
+ }
+ #endif
+ data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);
+ if (data)
+ return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
+ return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
+}
+
+STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+ return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+ float *result;
+ FILE *f = stbi__fopen(filename, "rb");
+ if (!f) return stbi__errpf("can't fopen", "Unable to open file");
+ result = stbi_loadf_from_file(f,x,y,comp,req_comp);
+ fclose(f);
+ return result;
+}
+
+STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_file(&s,f);
+ return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+#endif // !STBI_NO_STDIO
+
+#endif // !STBI_NO_LINEAR
+
+// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is
+// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always
+// reports false!
+
+STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
+{
+ #ifndef STBI_NO_HDR
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__hdr_test(&s);
+ #else
+ STBI_NOTUSED(buffer);
+ STBI_NOTUSED(len);
+ return 0;
+ #endif
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_is_hdr (char const *filename)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ int result=0;
+ if (f) {
+ result = stbi_is_hdr_from_file(f);
+ fclose(f);
+ }
+ return result;
+}
+
+STBIDEF int stbi_is_hdr_from_file(FILE *f)
+{
+ #ifndef STBI_NO_HDR
+ stbi__context s;
+ stbi__start_file(&s,f);
+ return stbi__hdr_test(&s);
+ #else
+ STBI_NOTUSED(f);
+ return 0;
+ #endif
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)
+{
+ #ifndef STBI_NO_HDR
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+ return stbi__hdr_test(&s);
+ #else
+ STBI_NOTUSED(clbk);
+ STBI_NOTUSED(user);
+ return 0;
+ #endif
+}
+
+#ifndef STBI_NO_LINEAR
+static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;
+
+STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }
+STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }
+#endif
+
+static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
+
+STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
+STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Common code used by all image loaders
+//
+
+enum
+{
+ STBI__SCAN_load=0,
+ STBI__SCAN_type,
+ STBI__SCAN_header
+};
+
+static void stbi__refill_buffer(stbi__context *s)
+{
+ int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
+ if (n == 0) {
+ // at end of file, treat same as if from memory, but need to handle case
+ // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file
+ s->read_from_callbacks = 0;
+ s->img_buffer = s->buffer_start;
+ s->img_buffer_end = s->buffer_start+1;
+ *s->img_buffer = 0;
+ } else {
+ s->img_buffer = s->buffer_start;
+ s->img_buffer_end = s->buffer_start + n;
+ }
+}
+
+stbi_inline static stbi_uc stbi__get8(stbi__context *s)
+{
+ if (s->img_buffer < s->img_buffer_end)
+ return *s->img_buffer++;
+ if (s->read_from_callbacks) {
+ stbi__refill_buffer(s);
+ return *s->img_buffer++;
+ }
+ return 0;
+}
+
+stbi_inline static int stbi__at_eof(stbi__context *s)
+{
+ if (s->io.read) {
+ if (!(s->io.eof)(s->io_user_data)) return 0;
+ // if feof() is true, check if buffer = end
+ // special case: we've only got the special 0 character at the end
+ if (s->read_from_callbacks == 0) return 1;
+ }
+
+ return s->img_buffer >= s->img_buffer_end;
+}
+
+static void stbi__skip(stbi__context *s, int n)
+{
+ if (n < 0) {
+ s->img_buffer = s->img_buffer_end;
+ return;
+ }
+ if (s->io.read) {
+ int blen = (int) (s->img_buffer_end - s->img_buffer);
+ if (blen < n) {
+ s->img_buffer = s->img_buffer_end;
+ (s->io.skip)(s->io_user_data, n - blen);
+ return;
+ }
+ }
+ s->img_buffer += n;
+}
+
+static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
+{
+ if (s->io.read) {
+ int blen = (int) (s->img_buffer_end - s->img_buffer);
+ if (blen < n) {
+ int res, count;
+
+ memcpy(buffer, s->img_buffer, blen);
+
+ count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);
+ res = (count == (n-blen));
+ s->img_buffer = s->img_buffer_end;
+ return res;
+ }
+ }
+
+ if (s->img_buffer+n <= s->img_buffer_end) {
+ memcpy(buffer, s->img_buffer, n);
+ s->img_buffer += n;
+ return 1;
+ } else
+ return 0;
+}
+
+static int stbi__get16be(stbi__context *s)
+{
+ int z = stbi__get8(s);
+ return (z << 8) + stbi__get8(s);
+}
+
+static stbi__uint32 stbi__get32be(stbi__context *s)
+{
+ stbi__uint32 z = stbi__get16be(s);
+ return (z << 16) + stbi__get16be(s);
+}
+
+#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)
+// nothing
+#else
+static int stbi__get16le(stbi__context *s)
+{
+ int z = stbi__get8(s);
+ return z + (stbi__get8(s) << 8);
+}
+#endif
+
+#ifndef STBI_NO_BMP
+static stbi__uint32 stbi__get32le(stbi__context *s)
+{
+ stbi__uint32 z = stbi__get16le(s);
+ return z + (stbi__get16le(s) << 16);
+}
+#endif
+
+#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// generic converter from built-in img_n to req_comp
+// individual types do this automatically as much as possible (e.g. jpeg
+// does all cases internally since it needs to colorspace convert anyway,
+// and it never has alpha, so very few cases ). png can automatically
+// interleave an alpha=255 channel, but falls back to this for other cases
+//
+// assume data buffer is malloced, so malloc a new one and free that one
+// only failure mode is malloc failing
+
+static stbi_uc stbi__compute_y(int r, int g, int b)
+{
+ return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8);
+}
+
+static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+ int i,j;
+ unsigned char *good;
+
+ if (req_comp == img_n) return data;
+ STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+ good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);
+ if (good == NULL) {
+ STBI_FREE(data);
+ return stbi__errpuc("outofmem", "Out of memory");
+ }
+
+ for (j=0; j < (int) y; ++j) {
+ unsigned char *src = data + j * x * img_n ;
+ unsigned char *dest = good + j * x * req_comp;
+
+ #define STBI__COMBO(a,b) ((a)*8+(b))
+ #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+ // convert source image with img_n components to one with req_comp components;
+ // avoid switch per pixel, so use switch per scanline and massive macros
+ switch (STBI__COMBO(img_n, req_comp)) {
+ STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break;
+ STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break;
+ STBI__CASE(2,1) { dest[0]=src[0]; } break;
+ STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
+ STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break;
+ STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
+ STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break;
+ STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
+ STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break;
+ STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
+ default: STBI_ASSERT(0);
+ }
+ #undef STBI__CASE
+ }
+
+ STBI_FREE(data);
+ return good;
+}
+
+static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
+{
+ return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8);
+}
+
+static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+ int i,j;
+ stbi__uint16 *good;
+
+ if (req_comp == img_n) return data;
+ STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+ good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);
+ if (good == NULL) {
+ STBI_FREE(data);
+ return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
+ }
+
+ for (j=0; j < (int) y; ++j) {
+ stbi__uint16 *src = data + j * x * img_n ;
+ stbi__uint16 *dest = good + j * x * req_comp;
+
+ #define STBI__COMBO(a,b) ((a)*8+(b))
+ #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+ // convert source image with img_n components to one with req_comp components;
+ // avoid switch per pixel, so use switch per scanline and massive macros
+ switch (STBI__COMBO(img_n, req_comp)) {
+ STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break;
+ STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break;
+ STBI__CASE(2,1) { dest[0]=src[0]; } break;
+ STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
+ STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break;
+ STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
+ STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break;
+ STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
+ STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break;
+ STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
+ default: STBI_ASSERT(0);
+ }
+ #undef STBI__CASE
+ }
+
+ STBI_FREE(data);
+ return good;
+}
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
+{
+ int i,k,n;
+ float *output;
+ if (!data) return NULL;
+ output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0);
+ if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); }
+ // compute number of non-alpha components
+ if (comp & 1) n = comp; else n = comp-1;
+ for (i=0; i < x*y; ++i) {
+ for (k=0; k < n; ++k) {
+ output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);
+ }
+ if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f;
+ }
+ STBI_FREE(data);
+ return output;
+}
+#endif
+
+#ifndef STBI_NO_HDR
+#define stbi__float2int(x) ((int) (x))
+static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp)
+{
+ int i,k,n;
+ stbi_uc *output;
+ if (!data) return NULL;
+ output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0);
+ if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); }
+ // compute number of non-alpha components
+ if (comp & 1) n = comp; else n = comp-1;
+ for (i=0; i < x*y; ++i) {
+ for (k=0; k < n; ++k) {
+ float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;
+ if (z < 0) z = 0;
+ if (z > 255) z = 255;
+ output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+ }
+ if (k < comp) {
+ float z = data[i*comp+k] * 255 + 0.5f;
+ if (z < 0) z = 0;
+ if (z > 255) z = 255;
+ output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+ }
+ }
+ STBI_FREE(data);
+ return output;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// "baseline" JPEG/JFIF decoder
+//
+// simple implementation
+// - doesn't support delayed output of y-dimension
+// - simple interface (only one output format: 8-bit interleaved RGB)
+// - doesn't try to recover corrupt jpegs
+// - doesn't allow partial loading, loading multiple at once
+// - still fast on x86 (copying globals into locals doesn't help x86)
+// - allocates lots of intermediate memory (full size of all components)
+// - non-interleaved case requires this anyway
+// - allows good upsampling (see next)
+// high-quality
+// - upsampled channels are bilinearly interpolated, even across blocks
+// - quality integer IDCT derived from IJG's 'slow'
+// performance
+// - fast huffman; reasonable integer IDCT
+// - some SIMD kernels for common paths on targets with SSE2/NEON
+// - uses a lot of intermediate memory, could cache poorly
+
+#ifndef STBI_NO_JPEG
+
+// huffman decoding acceleration
+#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache
+
+typedef struct
+{
+ stbi_uc fast[1 << FAST_BITS];
+ // weirdly, repacking this into AoS is a 10% speed loss, instead of a win
+ stbi__uint16 code[256];
+ stbi_uc values[256];
+ stbi_uc size[257];
+ unsigned int maxcode[18];
+ int delta[17]; // old 'firstsymbol' - old 'firstcode'
+} stbi__huffman;
+
+typedef struct
+{
+ stbi__context *s;
+ stbi__huffman huff_dc[4];
+ stbi__huffman huff_ac[4];
+ stbi_uc dequant[4][64];
+ stbi__int16 fast_ac[4][1 << FAST_BITS];
+
+// sizes for components, interleaved MCUs
+ int img_h_max, img_v_max;
+ int img_mcu_x, img_mcu_y;
+ int img_mcu_w, img_mcu_h;
+
+// definition of jpeg image component
+ struct
+ {
+ int id;
+ int h,v;
+ int tq;
+ int hd,ha;
+ int dc_pred;
+
+ int x,y,w2,h2;
+ stbi_uc *data;
+ void *raw_data, *raw_coeff;
+ stbi_uc *linebuf;
+ short *coeff; // progressive only
+ int coeff_w, coeff_h; // number of 8x8 coefficient blocks
+ } img_comp[4];
+
+ stbi__uint32 code_buffer; // jpeg entropy-coded buffer
+ int code_bits; // number of valid bits
+ unsigned char marker; // marker seen while filling entropy buffer
+ int nomore; // flag if we saw a marker so must stop
+
+ int progressive;
+ int spec_start;
+ int spec_end;
+ int succ_high;
+ int succ_low;
+ int eob_run;
+ int rgb;
+
+ int scan_n, order[4];
+ int restart_interval, todo;
+
+// kernels
+ void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);
+ void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);
+ stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);
+} stbi__jpeg;
+
+static int stbi__build_huffman(stbi__huffman *h, int *count)
+{
+ int i,j,k=0,code;
+ // build size list for each symbol (from JPEG spec)
+ for (i=0; i < 16; ++i)
+ for (j=0; j < count[i]; ++j)
+ h->size[k++] = (stbi_uc) (i+1);
+ h->size[k] = 0;
+
+ // compute actual symbols (from jpeg spec)
+ code = 0;
+ k = 0;
+ for(j=1; j <= 16; ++j) {
+ // compute delta to add to code to compute symbol id
+ h->delta[j] = k - code;
+ if (h->size[k] == j) {
+ while (h->size[k] == j)
+ h->code[k++] = (stbi__uint16) (code++);
+ if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG");
+ }
+ // compute largest code + 1 for this size, preshifted as needed later
+ h->maxcode[j] = code << (16-j);
+ code <<= 1;
+ }
+ h->maxcode[j] = 0xffffffff;
+
+ // build non-spec acceleration table; 255 is flag for not-accelerated
+ memset(h->fast, 255, 1 << FAST_BITS);
+ for (i=0; i < k; ++i) {
+ int s = h->size[i];
+ if (s <= FAST_BITS) {
+ int c = h->code[i] << (FAST_BITS-s);
+ int m = 1 << (FAST_BITS-s);
+ for (j=0; j < m; ++j) {
+ h->fast[c+j] = (stbi_uc) i;
+ }
+ }
+ }
+ return 1;
+}
+
+// build a table that decodes both magnitude and value of small ACs in
+// one go.
+static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
+{
+ int i;
+ for (i=0; i < (1 << FAST_BITS); ++i) {
+ stbi_uc fast = h->fast[i];
+ fast_ac[i] = 0;
+ if (fast < 255) {
+ int rs = h->values[fast];
+ int run = (rs >> 4) & 15;
+ int magbits = rs & 15;
+ int len = h->size[fast];
+
+ if (magbits && len + magbits <= FAST_BITS) {
+ // magnitude code followed by receive_extend code
+ int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);
+ int m = 1 << (magbits - 1);
+ if (k < m) k += (-1 << magbits) + 1;
+ // if the result is small enough, we can fit it in fast_ac table
+ if (k >= -128 && k <= 127)
+ fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits));
+ }
+ }
+ }
+}
+
+static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
+{
+ do {
+ int b = j->nomore ? 0 : stbi__get8(j->s);
+ if (b == 0xff) {
+ int c = stbi__get8(j->s);
+ if (c != 0) {
+ j->marker = (unsigned char) c;
+ j->nomore = 1;
+ return;
+ }
+ }
+ j->code_buffer |= b << (24 - j->code_bits);
+ j->code_bits += 8;
+ } while (j->code_bits <= 24);
+}
+
+// (1 << n) - 1
+static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
+
+// decode a jpeg huffman value from the bitstream
+stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
+{
+ unsigned int temp;
+ int c,k;
+
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+ // look at the top FAST_BITS and determine what symbol ID it is,
+ // if the code is <= FAST_BITS
+ c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+ k = h->fast[c];
+ if (k < 255) {
+ int s = h->size[k];
+ if (s > j->code_bits)
+ return -1;
+ j->code_buffer <<= s;
+ j->code_bits -= s;
+ return h->values[k];
+ }
+
+ // naive test is to shift the code_buffer down so k bits are
+ // valid, then test against maxcode. To speed this up, we've
+ // preshifted maxcode left so that it has (16-k) 0s at the
+ // end; in other words, regardless of the number of bits, it
+ // wants to be compared against something shifted to have 16;
+ // that way we don't need to shift inside the loop.
+ temp = j->code_buffer >> 16;
+ for (k=FAST_BITS+1 ; ; ++k)
+ if (temp < h->maxcode[k])
+ break;
+ if (k == 17) {
+ // error! code not found
+ j->code_bits -= 16;
+ return -1;
+ }
+
+ if (k > j->code_bits)
+ return -1;
+
+ // convert the huffman code to the symbol id
+ c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];
+ STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
+
+ // convert the id to a symbol
+ j->code_bits -= k;
+ j->code_buffer <<= k;
+ return h->values[c];
+}
+
+// bias[n] = (-1<<n) + 1
+static int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
+
+// combined JPEG 'receive' and JPEG 'extend', since baseline
+// always extends everything it receives.
+stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
+{
+ unsigned int k;
+ int sgn;
+ if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+
+ sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
+ k = stbi_lrot(j->code_buffer, n);
+ STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask)));
+ j->code_buffer = k & ~stbi__bmask[n];
+ k &= stbi__bmask[n];
+ j->code_bits -= n;
+ return k + (stbi__jbias[n] & ~sgn);
+}
+
+// get some unsigned bits
+stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
+{
+ unsigned int k;
+ if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+ k = stbi_lrot(j->code_buffer, n);
+ j->code_buffer = k & ~stbi__bmask[n];
+ k &= stbi__bmask[n];
+ j->code_bits -= n;
+ return k;
+}
+
+stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
+{
+ unsigned int k;
+ if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);
+ k = j->code_buffer;
+ j->code_buffer <<= 1;
+ --j->code_bits;
+ return k & 0x80000000;
+}
+
+// given a value that's at position X in the zigzag stream,
+// where does it appear in the 8x8 matrix coded as row-major?
+static stbi_uc stbi__jpeg_dezigzag[64+15] =
+{
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+ // let corrupt input sample past end
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63
+};
+
+// decode one 64-entry block--
+static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant)
+{
+ int diff,dc,k;
+ int t;
+
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+ t = stbi__jpeg_huff_decode(j, hdc);
+ if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+
+ // 0 all the ac values now so we can do it 32-bits at a time
+ memset(data,0,64*sizeof(data[0]));
+
+ diff = t ? stbi__extend_receive(j, t) : 0;
+ dc = j->img_comp[b].dc_pred + diff;
+ j->img_comp[b].dc_pred = dc;
+ data[0] = (short) (dc * dequant[0]);
+
+ // decode AC components, see JPEG spec
+ k = 1;
+ do {
+ unsigned int zig;
+ int c,r,s;
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+ c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+ r = fac[c];
+ if (r) { // fast-AC path
+ k += (r >> 4) & 15; // run
+ s = r & 15; // combined length
+ j->code_buffer <<= s;
+ j->code_bits -= s;
+ // decode into unzigzag'd location
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) ((r >> 8) * dequant[zig]);
+ } else {
+ int rs = stbi__jpeg_huff_decode(j, hac);
+ if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ s = rs & 15;
+ r = rs >> 4;
+ if (s == 0) {
+ if (rs != 0xf0) break; // end block
+ k += 16;
+ } else {
+ k += r;
+ // decode into unzigzag'd location
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);
+ }
+ }
+ } while (k < 64);
+ return 1;
+}
+
+static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)
+{
+ int diff,dc;
+ int t;
+ if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+ if (j->succ_high == 0) {
+ // first scan for DC coefficient, must be first
+ memset(data,0,64*sizeof(data[0])); // 0 all the ac values now
+ t = stbi__jpeg_huff_decode(j, hdc);
+ diff = t ? stbi__extend_receive(j, t) : 0;
+
+ dc = j->img_comp[b].dc_pred + diff;
+ j->img_comp[b].dc_pred = dc;
+ data[0] = (short) (dc << j->succ_low);
+ } else {
+ // refinement scan for DC coefficient
+ if (stbi__jpeg_get_bit(j))
+ data[0] += (short) (1 << j->succ_low);
+ }
+ return 1;
+}
+
+// @OPTIMIZE: store non-zigzagged during the decode passes,
+// and only de-zigzag when dequantizing
+static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)
+{
+ int k;
+ if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+ if (j->succ_high == 0) {
+ int shift = j->succ_low;
+
+ if (j->eob_run) {
+ --j->eob_run;
+ return 1;
+ }
+
+ k = j->spec_start;
+ do {
+ unsigned int zig;
+ int c,r,s;
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+ c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+ r = fac[c];
+ if (r) { // fast-AC path
+ k += (r >> 4) & 15; // run
+ s = r & 15; // combined length
+ j->code_buffer <<= s;
+ j->code_bits -= s;
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) ((r >> 8) << shift);
+ } else {
+ int rs = stbi__jpeg_huff_decode(j, hac);
+ if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ s = rs & 15;
+ r = rs >> 4;
+ if (s == 0) {
+ if (r < 15) {
+ j->eob_run = (1 << r);
+ if (r)
+ j->eob_run += stbi__jpeg_get_bits(j, r);
+ --j->eob_run;
+ break;
+ }
+ k += 16;
+ } else {
+ k += r;
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) (stbi__extend_receive(j,s) << shift);
+ }
+ }
+ } while (k <= j->spec_end);
+ } else {
+ // refinement scan for these AC coefficients
+
+ short bit = (short) (1 << j->succ_low);
+
+ if (j->eob_run) {
+ --j->eob_run;
+ for (k = j->spec_start; k <= j->spec_end; ++k) {
+ short *p = &data[stbi__jpeg_dezigzag[k]];
+ if (*p != 0)
+ if (stbi__jpeg_get_bit(j))
+ if ((*p & bit)==0) {
+ if (*p > 0)
+ *p += bit;
+ else
+ *p -= bit;
+ }
+ }
+ } else {
+ k = j->spec_start;
+ do {
+ int r,s;
+ int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh
+ if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ s = rs & 15;
+ r = rs >> 4;
+ if (s == 0) {
+ if (r < 15) {
+ j->eob_run = (1 << r) - 1;
+ if (r)
+ j->eob_run += stbi__jpeg_get_bits(j, r);
+ r = 64; // force end of block
+ } else {
+ // r=15 s=0 should write 16 0s, so we just do
+ // a run of 15 0s and then write s (which is 0),
+ // so we don't have to do anything special here
+ }
+ } else {
+ if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
+ // sign bit
+ if (stbi__jpeg_get_bit(j))
+ s = bit;
+ else
+ s = -bit;
+ }
+
+ // advance by r
+ while (k <= j->spec_end) {
+ short *p = &data[stbi__jpeg_dezigzag[k++]];
+ if (*p != 0) {
+ if (stbi__jpeg_get_bit(j))
+ if ((*p & bit)==0) {
+ if (*p > 0)
+ *p += bit;
+ else
+ *p -= bit;
+ }
+ } else {
+ if (r == 0) {
+ *p = (short) s;
+ break;
+ }
+ --r;
+ }
+ }
+ } while (k <= j->spec_end);
+ }
+ }
+ return 1;
+}
+
+// take a -128..127 value and stbi__clamp it and convert to 0..255
+stbi_inline static stbi_uc stbi__clamp(int x)
+{
+ // trick to use a single test to catch both cases
+ if ((unsigned int) x > 255) {
+ if (x < 0) return 0;
+ if (x > 255) return 255;
+ }
+ return (stbi_uc) x;
+}
+
+#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5)))
+#define stbi__fsh(x) ((x) << 12)
+
+// derived from jidctint -- DCT_ISLOW
+#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
+ int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \
+ p2 = s2; \
+ p3 = s6; \
+ p1 = (p2+p3) * stbi__f2f(0.5411961f); \
+ t2 = p1 + p3*stbi__f2f(-1.847759065f); \
+ t3 = p1 + p2*stbi__f2f( 0.765366865f); \
+ p2 = s0; \
+ p3 = s4; \
+ t0 = stbi__fsh(p2+p3); \
+ t1 = stbi__fsh(p2-p3); \
+ x0 = t0+t3; \
+ x3 = t0-t3; \
+ x1 = t1+t2; \
+ x2 = t1-t2; \
+ t0 = s7; \
+ t1 = s5; \
+ t2 = s3; \
+ t3 = s1; \
+ p3 = t0+t2; \
+ p4 = t1+t3; \
+ p1 = t0+t3; \
+ p2 = t1+t2; \
+ p5 = (p3+p4)*stbi__f2f( 1.175875602f); \
+ t0 = t0*stbi__f2f( 0.298631336f); \
+ t1 = t1*stbi__f2f( 2.053119869f); \
+ t2 = t2*stbi__f2f( 3.072711026f); \
+ t3 = t3*stbi__f2f( 1.501321110f); \
+ p1 = p5 + p1*stbi__f2f(-0.899976223f); \
+ p2 = p5 + p2*stbi__f2f(-2.562915447f); \
+ p3 = p3*stbi__f2f(-1.961570560f); \
+ p4 = p4*stbi__f2f(-0.390180644f); \
+ t3 += p1+p4; \
+ t2 += p2+p3; \
+ t1 += p2+p4; \
+ t0 += p1+p3;
+
+static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
+{
+ int i,val[64],*v=val;
+ stbi_uc *o;
+ short *d = data;
+
+ // columns
+ for (i=0; i < 8; ++i,++d, ++v) {
+ // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing
+ if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0
+ && d[40]==0 && d[48]==0 && d[56]==0) {
+ // no shortcut 0 seconds
+ // (1|2|3|4|5|6|7)==0 0 seconds
+ // all separate -0.047 seconds
+ // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds
+ int dcterm = d[0] << 2;
+ v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
+ } else {
+ STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
+ // constants scaled things up by 1<<12; let's bring them back
+ // down, but keep 2 extra bits of precision
+ x0 += 512; x1 += 512; x2 += 512; x3 += 512;
+ v[ 0] = (x0+t3) >> 10;
+ v[56] = (x0-t3) >> 10;
+ v[ 8] = (x1+t2) >> 10;
+ v[48] = (x1-t2) >> 10;
+ v[16] = (x2+t1) >> 10;
+ v[40] = (x2-t1) >> 10;
+ v[24] = (x3+t0) >> 10;
+ v[32] = (x3-t0) >> 10;
+ }
+ }
+
+ for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {
+ // no fast case since the first 1D IDCT spread components out
+ STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])
+ // constants scaled things up by 1<<12, plus we had 1<<2 from first
+ // loop, plus horizontal and vertical each scale by sqrt(8) so together
+ // we've got an extra 1<<3, so 1<<17 total we need to remove.
+ // so we want to round that, which means adding 0.5 * 1<<17,
+ // aka 65536. Also, we'll end up with -128 to 127 that we want
+ // to encode as 0..255 by adding 128, so we'll add that before the shift
+ x0 += 65536 + (128<<17);
+ x1 += 65536 + (128<<17);
+ x2 += 65536 + (128<<17);
+ x3 += 65536 + (128<<17);
+ // tried computing the shifts into temps, or'ing the temps to see
+ // if any were out of range, but that was slower
+ o[0] = stbi__clamp((x0+t3) >> 17);
+ o[7] = stbi__clamp((x0-t3) >> 17);
+ o[1] = stbi__clamp((x1+t2) >> 17);
+ o[6] = stbi__clamp((x1-t2) >> 17);
+ o[2] = stbi__clamp((x2+t1) >> 17);
+ o[5] = stbi__clamp((x2-t1) >> 17);
+ o[3] = stbi__clamp((x3+t0) >> 17);
+ o[4] = stbi__clamp((x3-t0) >> 17);
+ }
+}
+
+#ifdef STBI_SSE2
+// sse2 integer IDCT. not the fastest possible implementation but it
+// produces bit-identical results to the generic C version so it's
+// fully "transparent".
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+ // This is constructed to match our regular (generic) integer IDCT exactly.
+ __m128i row0, row1, row2, row3, row4, row5, row6, row7;
+ __m128i tmp;
+
+ // dot product constant: even elems=x, odd elems=y
+ #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))
+
+ // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit)
+ // out(1) = c1[even]*x + c1[odd]*y
+ #define dct_rot(out0,out1, x,y,c0,c1) \
+ __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \
+ __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \
+ __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \
+ __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \
+ __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \
+ __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)
+
+ // out = in << 12 (in 16-bit, out 32-bit)
+ #define dct_widen(out, in) \
+ __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \
+ __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)
+
+ // wide add
+ #define dct_wadd(out, a, b) \
+ __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \
+ __m128i out##_h = _mm_add_epi32(a##_h, b##_h)
+
+ // wide sub
+ #define dct_wsub(out, a, b) \
+ __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \
+ __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)
+
+ // butterfly a/b, add bias, then shift by "s" and pack
+ #define dct_bfly32o(out0, out1, a,b,bias,s) \
+ { \
+ __m128i abiased_l = _mm_add_epi32(a##_l, bias); \
+ __m128i abiased_h = _mm_add_epi32(a##_h, bias); \
+ dct_wadd(sum, abiased, b); \
+ dct_wsub(dif, abiased, b); \
+ out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \
+ out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \
+ }
+
+ // 8-bit interleave step (for transposes)
+ #define dct_interleave8(a, b) \
+ tmp = a; \
+ a = _mm_unpacklo_epi8(a, b); \
+ b = _mm_unpackhi_epi8(tmp, b)
+
+ // 16-bit interleave step (for transposes)
+ #define dct_interleave16(a, b) \
+ tmp = a; \
+ a = _mm_unpacklo_epi16(a, b); \
+ b = _mm_unpackhi_epi16(tmp, b)
+
+ #define dct_pass(bias,shift) \
+ { \
+ /* even part */ \
+ dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \
+ __m128i sum04 = _mm_add_epi16(row0, row4); \
+ __m128i dif04 = _mm_sub_epi16(row0, row4); \
+ dct_widen(t0e, sum04); \
+ dct_widen(t1e, dif04); \
+ dct_wadd(x0, t0e, t3e); \
+ dct_wsub(x3, t0e, t3e); \
+ dct_wadd(x1, t1e, t2e); \
+ dct_wsub(x2, t1e, t2e); \
+ /* odd part */ \
+ dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \
+ dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \
+ __m128i sum17 = _mm_add_epi16(row1, row7); \
+ __m128i sum35 = _mm_add_epi16(row3, row5); \
+ dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \
+ dct_wadd(x4, y0o, y4o); \
+ dct_wadd(x5, y1o, y5o); \
+ dct_wadd(x6, y2o, y5o); \
+ dct_wadd(x7, y3o, y4o); \
+ dct_bfly32o(row0,row7, x0,x7,bias,shift); \
+ dct_bfly32o(row1,row6, x1,x6,bias,shift); \
+ dct_bfly32o(row2,row5, x2,x5,bias,shift); \
+ dct_bfly32o(row3,row4, x3,x4,bias,shift); \
+ }
+
+ __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));
+ __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));
+ __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));
+ __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));
+ __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));
+ __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));
+ __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));
+ __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));
+
+ // rounding biases in column/row passes, see stbi__idct_block for explanation.
+ __m128i bias_0 = _mm_set1_epi32(512);
+ __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));
+
+ // load
+ row0 = _mm_load_si128((const __m128i *) (data + 0*8));
+ row1 = _mm_load_si128((const __m128i *) (data + 1*8));
+ row2 = _mm_load_si128((const __m128i *) (data + 2*8));
+ row3 = _mm_load_si128((const __m128i *) (data + 3*8));
+ row4 = _mm_load_si128((const __m128i *) (data + 4*8));
+ row5 = _mm_load_si128((const __m128i *) (data + 5*8));
+ row6 = _mm_load_si128((const __m128i *) (data + 6*8));
+ row7 = _mm_load_si128((const __m128i *) (data + 7*8));
+
+ // column pass
+ dct_pass(bias_0, 10);
+
+ {
+ // 16bit 8x8 transpose pass 1
+ dct_interleave16(row0, row4);
+ dct_interleave16(row1, row5);
+ dct_interleave16(row2, row6);
+ dct_interleave16(row3, row7);
+
+ // transpose pass 2
+ dct_interleave16(row0, row2);
+ dct_interleave16(row1, row3);
+ dct_interleave16(row4, row6);
+ dct_interleave16(row5, row7);
+
+ // transpose pass 3
+ dct_interleave16(row0, row1);
+ dct_interleave16(row2, row3);
+ dct_interleave16(row4, row5);
+ dct_interleave16(row6, row7);
+ }
+
+ // row pass
+ dct_pass(bias_1, 17);
+
+ {
+ // pack
+ __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7
+ __m128i p1 = _mm_packus_epi16(row2, row3);
+ __m128i p2 = _mm_packus_epi16(row4, row5);
+ __m128i p3 = _mm_packus_epi16(row6, row7);
+
+ // 8bit 8x8 transpose pass 1
+ dct_interleave8(p0, p2); // a0e0a1e1...
+ dct_interleave8(p1, p3); // c0g0c1g1...
+
+ // transpose pass 2
+ dct_interleave8(p0, p1); // a0c0e0g0...
+ dct_interleave8(p2, p3); // b0d0f0h0...
+
+ // transpose pass 3
+ dct_interleave8(p0, p2); // a0b0c0d0...
+ dct_interleave8(p1, p3); // a4b4c4d4...
+
+ // store
+ _mm_storel_epi64((__m128i *) out, p0); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, p2); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, p1); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, p3); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));
+ }
+
+#undef dct_const
+#undef dct_rot
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_interleave8
+#undef dct_interleave16
+#undef dct_pass
+}
+
+#endif // STBI_SSE2
+
+#ifdef STBI_NEON
+
+// NEON integer IDCT. should produce bit-identical
+// results to the generic C version.
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+ int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;
+
+ int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));
+ int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));
+ int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));
+ int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));
+ int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));
+ int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));
+ int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));
+ int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));
+ int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));
+ int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));
+ int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));
+ int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));
+
+#define dct_long_mul(out, inq, coeff) \
+ int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \
+ int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)
+
+#define dct_long_mac(out, acc, inq, coeff) \
+ int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \
+ int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)
+
+#define dct_widen(out, inq) \
+ int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \
+ int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)
+
+// wide add
+#define dct_wadd(out, a, b) \
+ int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \
+ int32x4_t out##_h = vaddq_s32(a##_h, b##_h)
+
+// wide sub
+#define dct_wsub(out, a, b) \
+ int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \
+ int32x4_t out##_h = vsubq_s32(a##_h, b##_h)
+
+// butterfly a/b, then shift using "shiftop" by "s" and pack
+#define dct_bfly32o(out0,out1, a,b,shiftop,s) \
+ { \
+ dct_wadd(sum, a, b); \
+ dct_wsub(dif, a, b); \
+ out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \
+ out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \
+ }
+
+#define dct_pass(shiftop, shift) \
+ { \
+ /* even part */ \
+ int16x8_t sum26 = vaddq_s16(row2, row6); \
+ dct_long_mul(p1e, sum26, rot0_0); \
+ dct_long_mac(t2e, p1e, row6, rot0_1); \
+ dct_long_mac(t3e, p1e, row2, rot0_2); \
+ int16x8_t sum04 = vaddq_s16(row0, row4); \
+ int16x8_t dif04 = vsubq_s16(row0, row4); \
+ dct_widen(t0e, sum04); \
+ dct_widen(t1e, dif04); \
+ dct_wadd(x0, t0e, t3e); \
+ dct_wsub(x3, t0e, t3e); \
+ dct_wadd(x1, t1e, t2e); \
+ dct_wsub(x2, t1e, t2e); \
+ /* odd part */ \
+ int16x8_t sum15 = vaddq_s16(row1, row5); \
+ int16x8_t sum17 = vaddq_s16(row1, row7); \
+ int16x8_t sum35 = vaddq_s16(row3, row5); \
+ int16x8_t sum37 = vaddq_s16(row3, row7); \
+ int16x8_t sumodd = vaddq_s16(sum17, sum35); \
+ dct_long_mul(p5o, sumodd, rot1_0); \
+ dct_long_mac(p1o, p5o, sum17, rot1_1); \
+ dct_long_mac(p2o, p5o, sum35, rot1_2); \
+ dct_long_mul(p3o, sum37, rot2_0); \
+ dct_long_mul(p4o, sum15, rot2_1); \
+ dct_wadd(sump13o, p1o, p3o); \
+ dct_wadd(sump24o, p2o, p4o); \
+ dct_wadd(sump23o, p2o, p3o); \
+ dct_wadd(sump14o, p1o, p4o); \
+ dct_long_mac(x4, sump13o, row7, rot3_0); \
+ dct_long_mac(x5, sump24o, row5, rot3_1); \
+ dct_long_mac(x6, sump23o, row3, rot3_2); \
+ dct_long_mac(x7, sump14o, row1, rot3_3); \
+ dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \
+ dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \
+ dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \
+ dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \
+ }
+
+ // load
+ row0 = vld1q_s16(data + 0*8);
+ row1 = vld1q_s16(data + 1*8);
+ row2 = vld1q_s16(data + 2*8);
+ row3 = vld1q_s16(data + 3*8);
+ row4 = vld1q_s16(data + 4*8);
+ row5 = vld1q_s16(data + 5*8);
+ row6 = vld1q_s16(data + 6*8);
+ row7 = vld1q_s16(data + 7*8);
+
+ // add DC bias
+ row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));
+
+ // column pass
+ dct_pass(vrshrn_n_s32, 10);
+
+ // 16bit 8x8 transpose
+ {
+// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.
+// whether compilers actually get this is another story, sadly.
+#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }
+#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }
+
+ // pass 1
+ dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6
+ dct_trn16(row2, row3);
+ dct_trn16(row4, row5);
+ dct_trn16(row6, row7);
+
+ // pass 2
+ dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4
+ dct_trn32(row1, row3);
+ dct_trn32(row4, row6);
+ dct_trn32(row5, row7);
+
+ // pass 3
+ dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0
+ dct_trn64(row1, row5);
+ dct_trn64(row2, row6);
+ dct_trn64(row3, row7);
+
+#undef dct_trn16
+#undef dct_trn32
+#undef dct_trn64
+ }
+
+ // row pass
+ // vrshrn_n_s32 only supports shifts up to 16, we need
+ // 17. so do a non-rounding shift of 16 first then follow
+ // up with a rounding shift by 1.
+ dct_pass(vshrn_n_s32, 16);
+
+ {
+ // pack and round
+ uint8x8_t p0 = vqrshrun_n_s16(row0, 1);
+ uint8x8_t p1 = vqrshrun_n_s16(row1, 1);
+ uint8x8_t p2 = vqrshrun_n_s16(row2, 1);
+ uint8x8_t p3 = vqrshrun_n_s16(row3, 1);
+ uint8x8_t p4 = vqrshrun_n_s16(row4, 1);
+ uint8x8_t p5 = vqrshrun_n_s16(row5, 1);
+ uint8x8_t p6 = vqrshrun_n_s16(row6, 1);
+ uint8x8_t p7 = vqrshrun_n_s16(row7, 1);
+
+ // again, these can translate into one instruction, but often don't.
+#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }
+#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }
+
+ // sadly can't use interleaved stores here since we only write
+ // 8 bytes to each scan line!
+
+ // 8x8 8-bit transpose pass 1
+ dct_trn8_8(p0, p1);
+ dct_trn8_8(p2, p3);
+ dct_trn8_8(p4, p5);
+ dct_trn8_8(p6, p7);
+
+ // pass 2
+ dct_trn8_16(p0, p2);
+ dct_trn8_16(p1, p3);
+ dct_trn8_16(p4, p6);
+ dct_trn8_16(p5, p7);
+
+ // pass 3
+ dct_trn8_32(p0, p4);
+ dct_trn8_32(p1, p5);
+ dct_trn8_32(p2, p6);
+ dct_trn8_32(p3, p7);
+
+ // store
+ vst1_u8(out, p0); out += out_stride;
+ vst1_u8(out, p1); out += out_stride;
+ vst1_u8(out, p2); out += out_stride;
+ vst1_u8(out, p3); out += out_stride;
+ vst1_u8(out, p4); out += out_stride;
+ vst1_u8(out, p5); out += out_stride;
+ vst1_u8(out, p6); out += out_stride;
+ vst1_u8(out, p7);
+
+#undef dct_trn8_8
+#undef dct_trn8_16
+#undef dct_trn8_32
+ }
+
+#undef dct_long_mul
+#undef dct_long_mac
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_pass
+}
+
+#endif // STBI_NEON
+
+#define STBI__MARKER_none 0xff
+// if there's a pending marker from the entropy stream, return that
+// otherwise, fetch from the stream and get a marker. if there's no
+// marker, return 0xff, which is never a valid marker value
+static stbi_uc stbi__get_marker(stbi__jpeg *j)
+{
+ stbi_uc x;
+ if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }
+ x = stbi__get8(j->s);
+ if (x != 0xff) return STBI__MARKER_none;
+ while (x == 0xff)
+ x = stbi__get8(j->s);
+ return x;
+}
+
+// in each scan, we'll have scan_n components, and the order
+// of the components is specified by order[]
+#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7)
+
+// after a restart interval, stbi__jpeg_reset the entropy decoder and
+// the dc prediction
+static void stbi__jpeg_reset(stbi__jpeg *j)
+{
+ j->code_bits = 0;
+ j->code_buffer = 0;
+ j->nomore = 0;
+ j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0;
+ j->marker = STBI__MARKER_none;
+ j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;
+ j->eob_run = 0;
+ // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,
+ // since we don't even allow 1<<30 pixels
+}
+
+static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
+{
+ stbi__jpeg_reset(z);
+ if (!z->progressive) {
+ if (z->scan_n == 1) {
+ int i,j;
+ STBI_SIMD_ALIGN(short, data[64]);
+ int n = z->order[0];
+ // non-interleaved data, we just need to process one block at a time,
+ // in trivial scanline order
+ // number of blocks to do just depends on how many actual "pixels" this
+ // component has, independent of interleaved MCU blocking and such
+ int w = (z->img_comp[n].x+7) >> 3;
+ int h = (z->img_comp[n].y+7) >> 3;
+ for (j=0; j < h; ++j) {
+ for (i=0; i < w; ++i) {
+ int ha = z->img_comp[n].ha;
+ if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+ z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+ // every data block is an MCU, so countdown the restart interval
+ if (--z->todo <= 0) {
+ if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+ // if it's NOT a restart, then just bail, so we get corrupt data
+ // rather than no data
+ if (!STBI__RESTART(z->marker)) return 1;
+ stbi__jpeg_reset(z);
+ }
+ }
+ }
+ return 1;
+ } else { // interleaved
+ int i,j,k,x,y;
+ STBI_SIMD_ALIGN(short, data[64]);
+ for (j=0; j < z->img_mcu_y; ++j) {
+ for (i=0; i < z->img_mcu_x; ++i) {
+ // scan an interleaved mcu... process scan_n components in order
+ for (k=0; k < z->scan_n; ++k) {
+ int n = z->order[k];
+ // scan out an mcu's worth of this component; that's just determined
+ // by the basic H and V specified for the component
+ for (y=0; y < z->img_comp[n].v; ++y) {
+ for (x=0; x < z->img_comp[n].h; ++x) {
+ int x2 = (i*z->img_comp[n].h + x)*8;
+ int y2 = (j*z->img_comp[n].v + y)*8;
+ int ha = z->img_comp[n].ha;
+ if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+ z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);
+ }
+ }
+ }
+ // after all interleaved components, that's an interleaved MCU,
+ // so now count down the restart interval
+ if (--z->todo <= 0) {
+ if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+ if (!STBI__RESTART(z->marker)) return 1;
+ stbi__jpeg_reset(z);
+ }
+ }
+ }
+ return 1;
+ }
+ } else {
+ if (z->scan_n == 1) {
+ int i,j;
+ int n = z->order[0];
+ // non-interleaved data, we just need to process one block at a time,
+ // in trivial scanline order
+ // number of blocks to do just depends on how many actual "pixels" this
+ // component has, independent of interleaved MCU blocking and such
+ int w = (z->img_comp[n].x+7) >> 3;
+ int h = (z->img_comp[n].y+7) >> 3;
+ for (j=0; j < h; ++j) {
+ for (i=0; i < w; ++i) {
+ short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+ if (z->spec_start == 0) {
+ if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+ return 0;
+ } else {
+ int ha = z->img_comp[n].ha;
+ if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))
+ return 0;
+ }
+ // every data block is an MCU, so countdown the restart interval
+ if (--z->todo <= 0) {
+ if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+ if (!STBI__RESTART(z->marker)) return 1;
+ stbi__jpeg_reset(z);
+ }
+ }
+ }
+ return 1;
+ } else { // interleaved
+ int i,j,k,x,y;
+ for (j=0; j < z->img_mcu_y; ++j) {
+ for (i=0; i < z->img_mcu_x; ++i) {
+ // scan an interleaved mcu... process scan_n components in order
+ for (k=0; k < z->scan_n; ++k) {
+ int n = z->order[k];
+ // scan out an mcu's worth of this component; that's just determined
+ // by the basic H and V specified for the component
+ for (y=0; y < z->img_comp[n].v; ++y) {
+ for (x=0; x < z->img_comp[n].h; ++x) {
+ int x2 = (i*z->img_comp[n].h + x);
+ int y2 = (j*z->img_comp[n].v + y);
+ short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
+ if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+ return 0;
+ }
+ }
+ }
+ // after all interleaved components, that's an interleaved MCU,
+ // so now count down the restart interval
+ if (--z->todo <= 0) {
+ if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+ if (!STBI__RESTART(z->marker)) return 1;
+ stbi__jpeg_reset(z);
+ }
+ }
+ }
+ return 1;
+ }
+ }
+}
+
+static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant)
+{
+ int i;
+ for (i=0; i < 64; ++i)
+ data[i] *= dequant[i];
+}
+
+static void stbi__jpeg_finish(stbi__jpeg *z)
+{
+ if (z->progressive) {
+ // dequantize and idct the data
+ int i,j,n;
+ for (n=0; n < z->s->img_n; ++n) {
+ int w = (z->img_comp[n].x+7) >> 3;
+ int h = (z->img_comp[n].y+7) >> 3;
+ for (j=0; j < h; ++j) {
+ for (i=0; i < w; ++i) {
+ short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+ stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);
+ z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+ }
+ }
+ }
+ }
+}
+
+static int stbi__process_marker(stbi__jpeg *z, int m)
+{
+ int L;
+ switch (m) {
+ case STBI__MARKER_none: // no marker found
+ return stbi__err("expected marker","Corrupt JPEG");
+
+ case 0xDD: // DRI - specify restart interval
+ if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG");
+ z->restart_interval = stbi__get16be(z->s);
+ return 1;
+
+ case 0xDB: // DQT - define quantization table
+ L = stbi__get16be(z->s)-2;
+ while (L > 0) {
+ int q = stbi__get8(z->s);
+ int p = q >> 4;
+ int t = q & 15,i;
+ if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG");
+ if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG");
+ for (i=0; i < 64; ++i)
+ z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s);
+ L -= 65;
+ }
+ return L==0;
+
+ case 0xC4: // DHT - define huffman table
+ L = stbi__get16be(z->s)-2;
+ while (L > 0) {
+ stbi_uc *v;
+ int sizes[16],i,n=0;
+ int q = stbi__get8(z->s);
+ int tc = q >> 4;
+ int th = q & 15;
+ if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG");
+ for (i=0; i < 16; ++i) {
+ sizes[i] = stbi__get8(z->s);
+ n += sizes[i];
+ }
+ L -= 17;
+ if (tc == 0) {
+ if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;
+ v = z->huff_dc[th].values;
+ } else {
+ if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;
+ v = z->huff_ac[th].values;
+ }
+ for (i=0; i < n; ++i)
+ v[i] = stbi__get8(z->s);
+ if (tc != 0)
+ stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);
+ L -= n;
+ }
+ return L==0;
+ }
+ // check for comment block or APP blocks
+ if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {
+ stbi__skip(z->s, stbi__get16be(z->s)-2);
+ return 1;
+ }
+ return 0;
+}
+
+// after we see SOS
+static int stbi__process_scan_header(stbi__jpeg *z)
+{
+ int i;
+ int Ls = stbi__get16be(z->s);
+ z->scan_n = stbi__get8(z->s);
+ if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG");
+ if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG");
+ for (i=0; i < z->scan_n; ++i) {
+ int id = stbi__get8(z->s), which;
+ int q = stbi__get8(z->s);
+ for (which = 0; which < z->s->img_n; ++which)
+ if (z->img_comp[which].id == id)
+ break;
+ if (which == z->s->img_n) return 0; // no match
+ z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG");
+ z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG");
+ z->order[i] = which;
+ }
+
+ {
+ int aa;
+ z->spec_start = stbi__get8(z->s);
+ z->spec_end = stbi__get8(z->s); // should be 63, but might be 0
+ aa = stbi__get8(z->s);
+ z->succ_high = (aa >> 4);
+ z->succ_low = (aa & 15);
+ if (z->progressive) {
+ if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)
+ return stbi__err("bad SOS", "Corrupt JPEG");
+ } else {
+ if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG");
+ if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG");
+ z->spec_end = 63;
+ }
+ }
+
+ return 1;
+}
+
+static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why)
+{
+ int i;
+ for (i=0; i < ncomp; ++i) {
+ if (z->img_comp[i].raw_data) {
+ STBI_FREE(z->img_comp[i].raw_data);
+ z->img_comp[i].raw_data = NULL;
+ z->img_comp[i].data = NULL;
+ }
+ if (z->img_comp[i].raw_coeff) {
+ STBI_FREE(z->img_comp[i].raw_coeff);
+ z->img_comp[i].raw_coeff = 0;
+ z->img_comp[i].coeff = 0;
+ }
+ if (z->img_comp[i].linebuf) {
+ STBI_FREE(z->img_comp[i].linebuf);
+ z->img_comp[i].linebuf = NULL;
+ }
+ }
+ return why;
+}
+
+static int stbi__process_frame_header(stbi__jpeg *z, int scan)
+{
+ stbi__context *s = z->s;
+ int Lf,p,i,q, h_max=1,v_max=1,c;
+ Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG
+ p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline
+ s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
+ s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires
+ c = stbi__get8(s);
+ if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG"); // JFIF requires
+ s->img_n = c;
+ for (i=0; i < c; ++i) {
+ z->img_comp[i].data = NULL;
+ z->img_comp[i].linebuf = NULL;
+ }
+
+ if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG");
+
+ z->rgb = 0;
+ for (i=0; i < s->img_n; ++i) {
+ static unsigned char rgb[3] = { 'R', 'G', 'B' };
+ z->img_comp[i].id = stbi__get8(s);
+ if (z->img_comp[i].id != i+1) // JFIF requires
+ if (z->img_comp[i].id != i) { // some version of jpegtran outputs non-JFIF-compliant files!
+ // somethings output this (see http://fileformats.archiveteam.org/wiki/JPEG#Color_format)
+ if (z->img_comp[i].id != rgb[i])
+ return stbi__err("bad component ID","Corrupt JPEG");
+ ++z->rgb;
+ }
+ q = stbi__get8(s);
+ z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG");
+ z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG");
+ z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG");
+ }
+
+ if (scan != STBI__SCAN_load) return 1;
+
+ if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode");
+
+ for (i=0; i < s->img_n; ++i) {
+ if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;
+ if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;
+ }
+
+ // compute interleaved mcu info
+ z->img_h_max = h_max;
+ z->img_v_max = v_max;
+ z->img_mcu_w = h_max * 8;
+ z->img_mcu_h = v_max * 8;
+ // these sizes can't be more than 17 bits
+ z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
+ z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
+
+ for (i=0; i < s->img_n; ++i) {
+ // number of effective pixels (e.g. for non-interleaved MCU)
+ z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
+ z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
+ // to simplify generation, we'll allocate enough memory to decode
+ // the bogus oversized data from using interleaved MCUs and their
+ // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
+ // discard the extra data until colorspace conversion
+ //
+ // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier)
+ // so these muls can't overflow with 32-bit ints (which we require)
+ z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;
+ z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;
+ z->img_comp[i].coeff = 0;
+ z->img_comp[i].raw_coeff = 0;
+ z->img_comp[i].linebuf = NULL;
+ z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15);
+ if (z->img_comp[i].raw_data == NULL)
+ return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
+ // align blocks for idct using mmx/sse
+ z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
+ if (z->progressive) {
+ // w2, h2 are multiples of 8 (see above)
+ z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8;
+ z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8;
+ z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15);
+ if (z->img_comp[i].raw_coeff == NULL)
+ return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
+ z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);
+ }
+ }
+
+ return 1;
+}
+
+// use comparisons since in some cases we handle more than one case (e.g. SOF)
+#define stbi__DNL(x) ((x) == 0xdc)
+#define stbi__SOI(x) ((x) == 0xd8)
+#define stbi__EOI(x) ((x) == 0xd9)
+#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)
+#define stbi__SOS(x) ((x) == 0xda)
+
+#define stbi__SOF_progressive(x) ((x) == 0xc2)
+
+static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
+{
+ int m;
+ z->marker = STBI__MARKER_none; // initialize cached marker to empty
+ m = stbi__get_marker(z);
+ if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG");
+ if (scan == STBI__SCAN_type) return 1;
+ m = stbi__get_marker(z);
+ while (!stbi__SOF(m)) {
+ if (!stbi__process_marker(z,m)) return 0;
+ m = stbi__get_marker(z);
+ while (m == STBI__MARKER_none) {
+ // some files have extra padding after their blocks, so ok, we'll scan
+ if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG");
+ m = stbi__get_marker(z);
+ }
+ }
+ z->progressive = stbi__SOF_progressive(m);
+ if (!stbi__process_frame_header(z, scan)) return 0;
+ return 1;
+}
+
+// decode image to YCbCr format
+static int stbi__decode_jpeg_image(stbi__jpeg *j)
+{
+ int m;
+ for (m = 0; m < 4; m++) {
+ j->img_comp[m].raw_data = NULL;
+ j->img_comp[m].raw_coeff = NULL;
+ }
+ j->restart_interval = 0;
+ if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;
+ m = stbi__get_marker(j);
+ while (!stbi__EOI(m)) {
+ if (stbi__SOS(m)) {
+ if (!stbi__process_scan_header(j)) return 0;
+ if (!stbi__parse_entropy_coded_data(j)) return 0;
+ if (j->marker == STBI__MARKER_none ) {
+ // handle 0s at the end of image data from IP Kamera 9060
+ while (!stbi__at_eof(j->s)) {
+ int x = stbi__get8(j->s);
+ if (x == 255) {
+ j->marker = stbi__get8(j->s);
+ break;
+ } else if (x != 0) {
+ return stbi__err("junk before marker", "Corrupt JPEG");
+ }
+ }
+ // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0
+ }
+ } else {
+ if (!stbi__process_marker(j, m)) return 0;
+ }
+ m = stbi__get_marker(j);
+ }
+ if (j->progressive)
+ stbi__jpeg_finish(j);
+ return 1;
+}
+
+// static jfif-centered resampling (across block boundaries)
+
+typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,
+ int w, int hs);
+
+#define stbi__div4(x) ((stbi_uc) ((x) >> 2))
+
+static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ STBI_NOTUSED(out);
+ STBI_NOTUSED(in_far);
+ STBI_NOTUSED(w);
+ STBI_NOTUSED(hs);
+ return in_near;
+}
+
+static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // need to generate two samples vertically for every one in input
+ int i;
+ STBI_NOTUSED(hs);
+ for (i=0; i < w; ++i)
+ out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);
+ return out;
+}
+
+static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // need to generate two samples horizontally for every one in input
+ int i;
+ stbi_uc *input = in_near;
+
+ if (w == 1) {
+ // if only one sample, can't do any interpolation
+ out[0] = out[1] = input[0];
+ return out;
+ }
+
+ out[0] = input[0];
+ out[1] = stbi__div4(input[0]*3 + input[1] + 2);
+ for (i=1; i < w-1; ++i) {
+ int n = 3*input[i]+2;
+ out[i*2+0] = stbi__div4(n+input[i-1]);
+ out[i*2+1] = stbi__div4(n+input[i+1]);
+ }
+ out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);
+ out[i*2+1] = input[w-1];
+
+ STBI_NOTUSED(in_far);
+ STBI_NOTUSED(hs);
+
+ return out;
+}
+
+#define stbi__div16(x) ((stbi_uc) ((x) >> 4))
+
+static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // need to generate 2x2 samples for every one in input
+ int i,t0,t1;
+ if (w == 1) {
+ out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+ return out;
+ }
+
+ t1 = 3*in_near[0] + in_far[0];
+ out[0] = stbi__div4(t1+2);
+ for (i=1; i < w; ++i) {
+ t0 = t1;
+ t1 = 3*in_near[i]+in_far[i];
+ out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+ out[i*2 ] = stbi__div16(3*t1 + t0 + 8);
+ }
+ out[w*2-1] = stbi__div4(t1+2);
+
+ STBI_NOTUSED(hs);
+
+ return out;
+}
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // need to generate 2x2 samples for every one in input
+ int i=0,t0,t1;
+
+ if (w == 1) {
+ out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+ return out;
+ }
+
+ t1 = 3*in_near[0] + in_far[0];
+ // process groups of 8 pixels for as long as we can.
+ // note we can't handle the last pixel in a row in this loop
+ // because we need to handle the filter boundary conditions.
+ for (; i < ((w-1) & ~7); i += 8) {
+#if defined(STBI_SSE2)
+ // load and perform the vertical filtering pass
+ // this uses 3*x + y = 4*x + (y - x)
+ __m128i zero = _mm_setzero_si128();
+ __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i));
+ __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));
+ __m128i farw = _mm_unpacklo_epi8(farb, zero);
+ __m128i nearw = _mm_unpacklo_epi8(nearb, zero);
+ __m128i diff = _mm_sub_epi16(farw, nearw);
+ __m128i nears = _mm_slli_epi16(nearw, 2);
+ __m128i curr = _mm_add_epi16(nears, diff); // current row
+
+ // horizontal filter works the same based on shifted vers of current
+ // row. "prev" is current row shifted right by 1 pixel; we need to
+ // insert the previous pixel value (from t1).
+ // "next" is current row shifted left by 1 pixel, with first pixel
+ // of next block of 8 pixels added in.
+ __m128i prv0 = _mm_slli_si128(curr, 2);
+ __m128i nxt0 = _mm_srli_si128(curr, 2);
+ __m128i prev = _mm_insert_epi16(prv0, t1, 0);
+ __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);
+
+ // horizontal filter, polyphase implementation since it's convenient:
+ // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+ // odd pixels = 3*cur + next = cur*4 + (next - cur)
+ // note the shared term.
+ __m128i bias = _mm_set1_epi16(8);
+ __m128i curs = _mm_slli_epi16(curr, 2);
+ __m128i prvd = _mm_sub_epi16(prev, curr);
+ __m128i nxtd = _mm_sub_epi16(next, curr);
+ __m128i curb = _mm_add_epi16(curs, bias);
+ __m128i even = _mm_add_epi16(prvd, curb);
+ __m128i odd = _mm_add_epi16(nxtd, curb);
+
+ // interleave even and odd pixels, then undo scaling.
+ __m128i int0 = _mm_unpacklo_epi16(even, odd);
+ __m128i int1 = _mm_unpackhi_epi16(even, odd);
+ __m128i de0 = _mm_srli_epi16(int0, 4);
+ __m128i de1 = _mm_srli_epi16(int1, 4);
+
+ // pack and write output
+ __m128i outv = _mm_packus_epi16(de0, de1);
+ _mm_storeu_si128((__m128i *) (out + i*2), outv);
+#elif defined(STBI_NEON)
+ // load and perform the vertical filtering pass
+ // this uses 3*x + y = 4*x + (y - x)
+ uint8x8_t farb = vld1_u8(in_far + i);
+ uint8x8_t nearb = vld1_u8(in_near + i);
+ int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));
+ int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));
+ int16x8_t curr = vaddq_s16(nears, diff); // current row
+
+ // horizontal filter works the same based on shifted vers of current
+ // row. "prev" is current row shifted right by 1 pixel; we need to
+ // insert the previous pixel value (from t1).
+ // "next" is current row shifted left by 1 pixel, with first pixel
+ // of next block of 8 pixels added in.
+ int16x8_t prv0 = vextq_s16(curr, curr, 7);
+ int16x8_t nxt0 = vextq_s16(curr, curr, 1);
+ int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);
+ int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);
+
+ // horizontal filter, polyphase implementation since it's convenient:
+ // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+ // odd pixels = 3*cur + next = cur*4 + (next - cur)
+ // note the shared term.
+ int16x8_t curs = vshlq_n_s16(curr, 2);
+ int16x8_t prvd = vsubq_s16(prev, curr);
+ int16x8_t nxtd = vsubq_s16(next, curr);
+ int16x8_t even = vaddq_s16(curs, prvd);
+ int16x8_t odd = vaddq_s16(curs, nxtd);
+
+ // undo scaling and round, then store with even/odd phases interleaved
+ uint8x8x2_t o;
+ o.val[0] = vqrshrun_n_s16(even, 4);
+ o.val[1] = vqrshrun_n_s16(odd, 4);
+ vst2_u8(out + i*2, o);
+#endif
+
+ // "previous" value for next iter
+ t1 = 3*in_near[i+7] + in_far[i+7];
+ }
+
+ t0 = t1;
+ t1 = 3*in_near[i] + in_far[i];
+ out[i*2] = stbi__div16(3*t1 + t0 + 8);
+
+ for (++i; i < w; ++i) {
+ t0 = t1;
+ t1 = 3*in_near[i]+in_far[i];
+ out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+ out[i*2 ] = stbi__div16(3*t1 + t0 + 8);
+ }
+ out[w*2-1] = stbi__div4(t1+2);
+
+ STBI_NOTUSED(hs);
+
+ return out;
+}
+#endif
+
+static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // resample with nearest-neighbor
+ int i,j;
+ STBI_NOTUSED(in_far);
+ for (i=0; i < w; ++i)
+ for (j=0; j < hs; ++j)
+ out[i*hs+j] = in_near[i];
+ return out;
+}
+
+#ifdef STBI_JPEG_OLD
+// this is the same YCbCr-to-RGB calculation that stb_image has used
+// historically before the algorithm changes in 1.49
+#define float2fixed(x) ((int) ((x) * 65536 + 0.5))
+static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
+{
+ int i;
+ for (i=0; i < count; ++i) {
+ int y_fixed = (y[i] << 16) + 32768; // rounding
+ int r,g,b;
+ int cr = pcr[i] - 128;
+ int cb = pcb[i] - 128;
+ r = y_fixed + cr*float2fixed(1.40200f);
+ g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f);
+ b = y_fixed + cb*float2fixed(1.77200f);
+ r >>= 16;
+ g >>= 16;
+ b >>= 16;
+ if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+ if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+ if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+ out[0] = (stbi_uc)r;
+ out[1] = (stbi_uc)g;
+ out[2] = (stbi_uc)b;
+ out[3] = 255;
+ out += step;
+ }
+}
+#else
+// this is a reduced-precision calculation of YCbCr-to-RGB introduced
+// to make sure the code produces the same results in both SIMD and scalar
+#define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8)
+static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
+{
+ int i;
+ for (i=0; i < count; ++i) {
+ int y_fixed = (y[i] << 20) + (1<<19); // rounding
+ int r,g,b;
+ int cr = pcr[i] - 128;
+ int cb = pcb[i] - 128;
+ r = y_fixed + cr* float2fixed(1.40200f);
+ g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000);
+ b = y_fixed + cb* float2fixed(1.77200f);
+ r >>= 20;
+ g >>= 20;
+ b >>= 20;
+ if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+ if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+ if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+ out[0] = (stbi_uc)r;
+ out[1] = (stbi_uc)g;
+ out[2] = (stbi_uc)b;
+ out[3] = 255;
+ out += step;
+ }
+}
+#endif
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)
+{
+ int i = 0;
+
+#ifdef STBI_SSE2
+ // step == 3 is pretty ugly on the final interleave, and i'm not convinced
+ // it's useful in practice (you wouldn't use it for textures, for example).
+ // so just accelerate step == 4 case.
+ if (step == 4) {
+ // this is a fairly straightforward implementation and not super-optimized.
+ __m128i signflip = _mm_set1_epi8(-0x80);
+ __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f));
+ __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
+ __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
+ __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f));
+ __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);
+ __m128i xw = _mm_set1_epi16(255); // alpha channel
+
+ for (; i+7 < count; i += 8) {
+ // load
+ __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));
+ __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));
+ __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));
+ __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128
+ __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128
+
+ // unpack to short (and left-shift cr, cb by 8)
+ __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes);
+ __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);
+ __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);
+
+ // color transform
+ __m128i yws = _mm_srli_epi16(yw, 4);
+ __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);
+ __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);
+ __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);
+ __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);
+ __m128i rws = _mm_add_epi16(cr0, yws);
+ __m128i gwt = _mm_add_epi16(cb0, yws);
+ __m128i bws = _mm_add_epi16(yws, cb1);
+ __m128i gws = _mm_add_epi16(gwt, cr1);
+
+ // descale
+ __m128i rw = _mm_srai_epi16(rws, 4);
+ __m128i bw = _mm_srai_epi16(bws, 4);
+ __m128i gw = _mm_srai_epi16(gws, 4);
+
+ // back to byte, set up for transpose
+ __m128i brb = _mm_packus_epi16(rw, bw);
+ __m128i gxb = _mm_packus_epi16(gw, xw);
+
+ // transpose to interleave channels
+ __m128i t0 = _mm_unpacklo_epi8(brb, gxb);
+ __m128i t1 = _mm_unpackhi_epi8(brb, gxb);
+ __m128i o0 = _mm_unpacklo_epi16(t0, t1);
+ __m128i o1 = _mm_unpackhi_epi16(t0, t1);
+
+ // store
+ _mm_storeu_si128((__m128i *) (out + 0), o0);
+ _mm_storeu_si128((__m128i *) (out + 16), o1);
+ out += 32;
+ }
+ }
+#endif
+
+#ifdef STBI_NEON
+ // in this version, step=3 support would be easy to add. but is there demand?
+ if (step == 4) {
+ // this is a fairly straightforward implementation and not super-optimized.
+ uint8x8_t signflip = vdup_n_u8(0x80);
+ int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f));
+ int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));
+ int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));
+ int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f));
+
+ for (; i+7 < count; i += 8) {
+ // load
+ uint8x8_t y_bytes = vld1_u8(y + i);
+ uint8x8_t cr_bytes = vld1_u8(pcr + i);
+ uint8x8_t cb_bytes = vld1_u8(pcb + i);
+ int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));
+ int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));
+
+ // expand to s16
+ int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));
+ int16x8_t crw = vshll_n_s8(cr_biased, 7);
+ int16x8_t cbw = vshll_n_s8(cb_biased, 7);
+
+ // color transform
+ int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);
+ int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);
+ int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);
+ int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);
+ int16x8_t rws = vaddq_s16(yws, cr0);
+ int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);
+ int16x8_t bws = vaddq_s16(yws, cb1);
+
+ // undo scaling, round, convert to byte
+ uint8x8x4_t o;
+ o.val[0] = vqrshrun_n_s16(rws, 4);
+ o.val[1] = vqrshrun_n_s16(gws, 4);
+ o.val[2] = vqrshrun_n_s16(bws, 4);
+ o.val[3] = vdup_n_u8(255);
+
+ // store, interleaving r/g/b/a
+ vst4_u8(out, o);
+ out += 8*4;
+ }
+ }
+#endif
+
+ for (; i < count; ++i) {
+ int y_fixed = (y[i] << 20) + (1<<19); // rounding
+ int r,g,b;
+ int cr = pcr[i] - 128;
+ int cb = pcb[i] - 128;
+ r = y_fixed + cr* float2fixed(1.40200f);
+ g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000);
+ b = y_fixed + cb* float2fixed(1.77200f);
+ r >>= 20;
+ g >>= 20;
+ b >>= 20;
+ if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+ if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+ if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+ out[0] = (stbi_uc)r;
+ out[1] = (stbi_uc)g;
+ out[2] = (stbi_uc)b;
+ out[3] = 255;
+ out += step;
+ }
+}
+#endif
+
+// set up the kernels
+static void stbi__setup_jpeg(stbi__jpeg *j)
+{
+ j->idct_block_kernel = stbi__idct_block;
+ j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;
+ j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;
+
+#ifdef STBI_SSE2
+ if (stbi__sse2_available()) {
+ j->idct_block_kernel = stbi__idct_simd;
+ #ifndef STBI_JPEG_OLD
+ j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+ #endif
+ j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+ }
+#endif
+
+#ifdef STBI_NEON
+ j->idct_block_kernel = stbi__idct_simd;
+ #ifndef STBI_JPEG_OLD
+ j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+ #endif
+ j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+#endif
+}
+
+// clean up the temporary component buffers
+static void stbi__cleanup_jpeg(stbi__jpeg *j)
+{
+ stbi__free_jpeg_components(j, j->s->img_n, 0);
+}
+
+typedef struct
+{
+ resample_row_func resample;
+ stbi_uc *line0,*line1;
+ int hs,vs; // expansion factor in each axis
+ int w_lores; // horizontal pixels pre-expansion
+ int ystep; // how far through vertical expansion we are
+ int ypos; // which pre-expansion row we're on
+} stbi__resample;
+
+static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)
+{
+ int n, decode_n;
+ z->s->img_n = 0; // make stbi__cleanup_jpeg safe
+
+ // validate req_comp
+ if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+
+ // load a jpeg image from whichever source, but leave in YCbCr format
+ if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }
+
+ // determine actual number of components to generate
+ n = req_comp ? req_comp : z->s->img_n;
+
+ if (z->s->img_n == 3 && n < 3)
+ decode_n = 1;
+ else
+ decode_n = z->s->img_n;
+
+ // resample and color-convert
+ {
+ int k;
+ unsigned int i,j;
+ stbi_uc *output;
+ stbi_uc *coutput[4];
+
+ stbi__resample res_comp[4];
+
+ for (k=0; k < decode_n; ++k) {
+ stbi__resample *r = &res_comp[k];
+
+ // allocate line buffer big enough for upsampling off the edges
+ // with upsample factor of 4
+ z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);
+ if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+ r->hs = z->img_h_max / z->img_comp[k].h;
+ r->vs = z->img_v_max / z->img_comp[k].v;
+ r->ystep = r->vs >> 1;
+ r->w_lores = (z->s->img_x + r->hs-1) / r->hs;
+ r->ypos = 0;
+ r->line0 = r->line1 = z->img_comp[k].data;
+
+ if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;
+ else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;
+ else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;
+ else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;
+ else r->resample = stbi__resample_row_generic;
+ }
+
+ // can't error after this so, this is safe
+ output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1);
+ if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+ // now go ahead and resample
+ for (j=0; j < z->s->img_y; ++j) {
+ stbi_uc *out = output + n * z->s->img_x * j;
+ for (k=0; k < decode_n; ++k) {
+ stbi__resample *r = &res_comp[k];
+ int y_bot = r->ystep >= (r->vs >> 1);
+ coutput[k] = r->resample(z->img_comp[k].linebuf,
+ y_bot ? r->line1 : r->line0,
+ y_bot ? r->line0 : r->line1,
+ r->w_lores, r->hs);
+ if (++r->ystep >= r->vs) {
+ r->ystep = 0;
+ r->line0 = r->line1;
+ if (++r->ypos < z->img_comp[k].y)
+ r->line1 += z->img_comp[k].w2;
+ }
+ }
+ if (n >= 3) {
+ stbi_uc *y = coutput[0];
+ if (z->s->img_n == 3) {
+ if (z->rgb == 3) {
+ for (i=0; i < z->s->img_x; ++i) {
+ out[0] = y[i];
+ out[1] = coutput[1][i];
+ out[2] = coutput[2][i];
+ out[3] = 255;
+ out += n;
+ }
+ } else {
+ z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+ }
+ } else
+ for (i=0; i < z->s->img_x; ++i) {
+ out[0] = out[1] = out[2] = y[i];
+ out[3] = 255; // not used if n==3
+ out += n;
+ }
+ } else {
+ stbi_uc *y = coutput[0];
+ if (n == 1)
+ for (i=0; i < z->s->img_x; ++i) out[i] = y[i];
+ else
+ for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255;
+ }
+ }
+ stbi__cleanup_jpeg(z);
+ *out_x = z->s->img_x;
+ *out_y = z->s->img_y;
+ if (comp) *comp = z->s->img_n; // report original components, not output
+ return output;
+ }
+}
+
+static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ unsigned char* result;
+ stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
+ j->s = s;
+ stbi__setup_jpeg(j);
+ result = load_jpeg_image(j, x,y,comp,req_comp);
+ STBI_FREE(j);
+ return result;
+}
+
+static int stbi__jpeg_test(stbi__context *s)
+{
+ int r;
+ stbi__jpeg j;
+ j.s = s;
+ stbi__setup_jpeg(&j);
+ r = stbi__decode_jpeg_header(&j, STBI__SCAN_type);
+ stbi__rewind(s);
+ return r;
+}
+
+static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)
+{
+ if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {
+ stbi__rewind( j->s );
+ return 0;
+ }
+ if (x) *x = j->s->img_x;
+ if (y) *y = j->s->img_y;
+ if (comp) *comp = j->s->img_n;
+ return 1;
+}
+
+static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int result;
+ stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));
+ j->s = s;
+ result = stbi__jpeg_info_raw(j, x, y, comp);
+ STBI_FREE(j);
+ return result;
+}
+#endif
+
+// public domain zlib decode v0.2 Sean Barrett 2006-11-18
+// simple implementation
+// - all input must be provided in an upfront buffer
+// - all output is written to a single output buffer (can malloc/realloc)
+// performance
+// - fast huffman
+
+#ifndef STBI_NO_ZLIB
+
+// fast-way is faster to check than jpeg huffman, but slow way is slower
+#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables
+#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1)
+
+// zlib-style huffman encoding
+// (jpegs packs from left, zlib from right, so can't share code)
+typedef struct
+{
+ stbi__uint16 fast[1 << STBI__ZFAST_BITS];
+ stbi__uint16 firstcode[16];
+ int maxcode[17];
+ stbi__uint16 firstsymbol[16];
+ stbi_uc size[288];
+ stbi__uint16 value[288];
+} stbi__zhuffman;
+
+stbi_inline static int stbi__bitreverse16(int n)
+{
+ n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1);
+ n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2);
+ n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4);
+ n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8);
+ return n;
+}
+
+stbi_inline static int stbi__bit_reverse(int v, int bits)
+{
+ STBI_ASSERT(bits <= 16);
+ // to bit reverse n bits, reverse 16 and shift
+ // e.g. 11 bits, bit reverse and shift away 5
+ return stbi__bitreverse16(v) >> (16-bits);
+}
+
+static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)
+{
+ int i,k=0;
+ int code, next_code[16], sizes[17];
+
+ // DEFLATE spec for generating codes
+ memset(sizes, 0, sizeof(sizes));
+ memset(z->fast, 0, sizeof(z->fast));
+ for (i=0; i < num; ++i)
+ ++sizes[sizelist[i]];
+ sizes[0] = 0;
+ for (i=1; i < 16; ++i)
+ if (sizes[i] > (1 << i))
+ return stbi__err("bad sizes", "Corrupt PNG");
+ code = 0;
+ for (i=1; i < 16; ++i) {
+ next_code[i] = code;
+ z->firstcode[i] = (stbi__uint16) code;
+ z->firstsymbol[i] = (stbi__uint16) k;
+ code = (code + sizes[i]);
+ if (sizes[i])
+ if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG");
+ z->maxcode[i] = code << (16-i); // preshift for inner loop
+ code <<= 1;
+ k += sizes[i];
+ }
+ z->maxcode[16] = 0x10000; // sentinel
+ for (i=0; i < num; ++i) {
+ int s = sizelist[i];
+ if (s) {
+ int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
+ stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);
+ z->size [c] = (stbi_uc ) s;
+ z->value[c] = (stbi__uint16) i;
+ if (s <= STBI__ZFAST_BITS) {
+ int j = stbi__bit_reverse(next_code[s],s);
+ while (j < (1 << STBI__ZFAST_BITS)) {
+ z->fast[j] = fastv;
+ j += (1 << s);
+ }
+ }
+ ++next_code[s];
+ }
+ }
+ return 1;
+}
+
+// zlib-from-memory implementation for PNG reading
+// because PNG allows splitting the zlib stream arbitrarily,
+// and it's annoying structurally to have PNG call ZLIB call PNG,
+// we require PNG read all the IDATs and combine them into a single
+// memory buffer
+
+typedef struct
+{
+ stbi_uc *zbuffer, *zbuffer_end;
+ int num_bits;
+ stbi__uint32 code_buffer;
+
+ char *zout;
+ char *zout_start;
+ char *zout_end;
+ int z_expandable;
+
+ stbi__zhuffman z_length, z_distance;
+} stbi__zbuf;
+
+stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)
+{
+ if (z->zbuffer >= z->zbuffer_end) return 0;
+ return *z->zbuffer++;
+}
+
+static void stbi__fill_bits(stbi__zbuf *z)
+{
+ do {
+ STBI_ASSERT(z->code_buffer < (1U << z->num_bits));
+ z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;
+ z->num_bits += 8;
+ } while (z->num_bits <= 24);
+}
+
+stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)
+{
+ unsigned int k;
+ if (z->num_bits < n) stbi__fill_bits(z);
+ k = z->code_buffer & ((1 << n) - 1);
+ z->code_buffer >>= n;
+ z->num_bits -= n;
+ return k;
+}
+
+static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
+{
+ int b,s,k;
+ // not resolved by fast table, so compute it the slow way
+ // use jpeg approach, which requires MSbits at top
+ k = stbi__bit_reverse(a->code_buffer, 16);
+ for (s=STBI__ZFAST_BITS+1; ; ++s)
+ if (k < z->maxcode[s])
+ break;
+ if (s == 16) return -1; // invalid code!
+ // code size is s, so:
+ b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
+ STBI_ASSERT(z->size[b] == s);
+ a->code_buffer >>= s;
+ a->num_bits -= s;
+ return z->value[b];
+}
+
+stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
+{
+ int b,s;
+ if (a->num_bits < 16) stbi__fill_bits(a);
+ b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
+ if (b) {
+ s = b >> 9;
+ a->code_buffer >>= s;
+ a->num_bits -= s;
+ return b & 511;
+ }
+ return stbi__zhuffman_decode_slowpath(a, z);
+}
+
+static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes
+{
+ char *q;
+ int cur, limit, old_limit;
+ z->zout = zout;
+ if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
+ cur = (int) (z->zout - z->zout_start);
+ limit = old_limit = (int) (z->zout_end - z->zout_start);
+ while (cur + n > limit)
+ limit *= 2;
+ q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
+ STBI_NOTUSED(old_limit);
+ if (q == NULL) return stbi__err("outofmem", "Out of memory");
+ z->zout_start = q;
+ z->zout = q + cur;
+ z->zout_end = q + limit;
+ return 1;
+}
+
+static int stbi__zlength_base[31] = {
+ 3,4,5,6,7,8,9,10,11,13,
+ 15,17,19,23,27,31,35,43,51,59,
+ 67,83,99,115,131,163,195,227,258,0,0 };
+
+static int stbi__zlength_extra[31]=
+{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
+
+static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
+257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
+
+static int stbi__zdist_extra[32] =
+{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+static int stbi__parse_huffman_block(stbi__zbuf *a)
+{
+ char *zout = a->zout;
+ for(;;) {
+ int z = stbi__zhuffman_decode(a, &a->z_length);
+ if (z < 256) {
+ if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes
+ if (zout >= a->zout_end) {
+ if (!stbi__zexpand(a, zout, 1)) return 0;
+ zout = a->zout;
+ }
+ *zout++ = (char) z;
+ } else {
+ stbi_uc *p;
+ int len,dist;
+ if (z == 256) {
+ a->zout = zout;
+ return 1;
+ }
+ z -= 257;
+ len = stbi__zlength_base[z];
+ if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
+ z = stbi__zhuffman_decode(a, &a->z_distance);
+ if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
+ dist = stbi__zdist_base[z];
+ if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
+ if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
+ if (zout + len > a->zout_end) {
+ if (!stbi__zexpand(a, zout, len)) return 0;
+ zout = a->zout;
+ }
+ p = (stbi_uc *) (zout - dist);
+ if (dist == 1) { // run of one byte; common in images.
+ stbi_uc v = *p;
+ if (len) { do *zout++ = v; while (--len); }
+ } else {
+ if (len) { do *zout++ = *p++; while (--len); }
+ }
+ }
+ }
+}
+
+static int stbi__compute_huffman_codes(stbi__zbuf *a)
+{
+ static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+ stbi__zhuffman z_codelength;
+ stbi_uc lencodes[286+32+137];//padding for maximum single op
+ stbi_uc codelength_sizes[19];
+ int i,n;
+
+ int hlit = stbi__zreceive(a,5) + 257;
+ int hdist = stbi__zreceive(a,5) + 1;
+ int hclen = stbi__zreceive(a,4) + 4;
+ int ntot = hlit + hdist;
+
+ memset(codelength_sizes, 0, sizeof(codelength_sizes));
+ for (i=0; i < hclen; ++i) {
+ int s = stbi__zreceive(a,3);
+ codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;
+ }
+ if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
+
+ n = 0;
+ while (n < ntot) {
+ int c = stbi__zhuffman_decode(a, &z_codelength);
+ if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
+ if (c < 16)
+ lencodes[n++] = (stbi_uc) c;
+ else {
+ stbi_uc fill = 0;
+ if (c == 16) {
+ c = stbi__zreceive(a,2)+3;
+ if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG");
+ fill = lencodes[n-1];
+ } else if (c == 17)
+ c = stbi__zreceive(a,3)+3;
+ else {
+ STBI_ASSERT(c == 18);
+ c = stbi__zreceive(a,7)+11;
+ }
+ if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG");
+ memset(lencodes+n, fill, c);
+ n += c;
+ }
+ }
+ if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG");
+ if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
+ if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
+ return 1;
+}
+
+static int stbi__parse_uncompressed_block(stbi__zbuf *a)
+{
+ stbi_uc header[4];
+ int len,nlen,k;
+ if (a->num_bits & 7)
+ stbi__zreceive(a, a->num_bits & 7); // discard
+ // drain the bit-packed data into header
+ k = 0;
+ while (a->num_bits > 0) {
+ header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check
+ a->code_buffer >>= 8;
+ a->num_bits -= 8;
+ }
+ STBI_ASSERT(a->num_bits == 0);
+ // now fill header the normal way
+ while (k < 4)
+ header[k++] = stbi__zget8(a);
+ len = header[1] * 256 + header[0];
+ nlen = header[3] * 256 + header[2];
+ if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG");
+ if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG");
+ if (a->zout + len > a->zout_end)
+ if (!stbi__zexpand(a, a->zout, len)) return 0;
+ memcpy(a->zout, a->zbuffer, len);
+ a->zbuffer += len;
+ a->zout += len;
+ return 1;
+}
+
+static int stbi__parse_zlib_header(stbi__zbuf *a)
+{
+ int cmf = stbi__zget8(a);
+ int cm = cmf & 15;
+ /* int cinfo = cmf >> 4; */
+ int flg = stbi__zget8(a);
+ if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
+ if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png
+ if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png
+ // window = 1 << (8 + cinfo)... but who cares, we fully buffer output
+ return 1;
+}
+
+// @TODO: should statically initialize these for optimal thread safety
+static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32];
+static void stbi__init_zdefaults(void)
+{
+ int i; // use <= to match clearly with spec
+ for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8;
+ for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9;
+ for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7;
+ for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8;
+
+ for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5;
+}
+
+static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
+{
+ int final, type;
+ if (parse_header)
+ if (!stbi__parse_zlib_header(a)) return 0;
+ a->num_bits = 0;
+ a->code_buffer = 0;
+ do {
+ final = stbi__zreceive(a,1);
+ type = stbi__zreceive(a,2);
+ if (type == 0) {
+ if (!stbi__parse_uncompressed_block(a)) return 0;
+ } else if (type == 3) {
+ return 0;
+ } else {
+ if (type == 1) {
+ // use fixed code lengths
+ if (!stbi__zdefault_distance[31]) stbi__init_zdefaults();
+ if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0;
+ if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0;
+ } else {
+ if (!stbi__compute_huffman_codes(a)) return 0;
+ }
+ if (!stbi__parse_huffman_block(a)) return 0;
+ }
+ } while (!final);
+ return 1;
+}
+
+static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)
+{
+ a->zout_start = obuf;
+ a->zout = obuf;
+ a->zout_end = obuf + olen;
+ a->z_expandable = exp;
+
+ return stbi__parse_zlib(a, parse_header);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)
+{
+ stbi__zbuf a;
+ char *p = (char *) stbi__malloc(initial_size);
+ if (p == NULL) return NULL;
+ a.zbuffer = (stbi_uc *) buffer;
+ a.zbuffer_end = (stbi_uc *) buffer + len;
+ if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {
+ if (outlen) *outlen = (int) (a.zout - a.zout_start);
+ return a.zout_start;
+ } else {
+ STBI_FREE(a.zout_start);
+ return NULL;
+ }
+}
+
+STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)
+{
+ return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
+{
+ stbi__zbuf a;
+ char *p = (char *) stbi__malloc(initial_size);
+ if (p == NULL) return NULL;
+ a.zbuffer = (stbi_uc *) buffer;
+ a.zbuffer_end = (stbi_uc *) buffer + len;
+ if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {
+ if (outlen) *outlen = (int) (a.zout - a.zout_start);
+ return a.zout_start;
+ } else {
+ STBI_FREE(a.zout_start);
+ return NULL;
+ }
+}
+
+STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)
+{
+ stbi__zbuf a;
+ a.zbuffer = (stbi_uc *) ibuffer;
+ a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+ if (stbi__do_zlib(&a, obuffer, olen, 0, 1))
+ return (int) (a.zout - a.zout_start);
+ else
+ return -1;
+}
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)
+{
+ stbi__zbuf a;
+ char *p = (char *) stbi__malloc(16384);
+ if (p == NULL) return NULL;
+ a.zbuffer = (stbi_uc *) buffer;
+ a.zbuffer_end = (stbi_uc *) buffer+len;
+ if (stbi__do_zlib(&a, p, 16384, 1, 0)) {
+ if (outlen) *outlen = (int) (a.zout - a.zout_start);
+ return a.zout_start;
+ } else {
+ STBI_FREE(a.zout_start);
+ return NULL;
+ }
+}
+
+STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)
+{
+ stbi__zbuf a;
+ a.zbuffer = (stbi_uc *) ibuffer;
+ a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+ if (stbi__do_zlib(&a, obuffer, olen, 0, 0))
+ return (int) (a.zout - a.zout_start);
+ else
+ return -1;
+}
+#endif
+
+// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18
+// simple implementation
+// - only 8-bit samples
+// - no CRC checking
+// - allocates lots of intermediate memory
+// - avoids problem of streaming data between subsystems
+// - avoids explicit window management
+// performance
+// - uses stb_zlib, a PD zlib implementation with fast huffman decoding
+
+#ifndef STBI_NO_PNG
+typedef struct
+{
+ stbi__uint32 length;
+ stbi__uint32 type;
+} stbi__pngchunk;
+
+static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
+{
+ stbi__pngchunk c;
+ c.length = stbi__get32be(s);
+ c.type = stbi__get32be(s);
+ return c;
+}
+
+static int stbi__check_png_header(stbi__context *s)
+{
+ static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
+ int i;
+ for (i=0; i < 8; ++i)
+ if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
+ return 1;
+}
+
+typedef struct
+{
+ stbi__context *s;
+ stbi_uc *idata, *expanded, *out;
+ int depth;
+} stbi__png;
+
+
+enum {
+ STBI__F_none=0,
+ STBI__F_sub=1,
+ STBI__F_up=2,
+ STBI__F_avg=3,
+ STBI__F_paeth=4,
+ // synthetic filters used for first scanline to avoid needing a dummy row of 0s
+ STBI__F_avg_first,
+ STBI__F_paeth_first
+};
+
+static stbi_uc first_row_filter[5] =
+{
+ STBI__F_none,
+ STBI__F_sub,
+ STBI__F_none,
+ STBI__F_avg_first,
+ STBI__F_paeth_first
+};
+
+static int stbi__paeth(int a, int b, int c)
+{
+ int p = a + b - c;
+ int pa = abs(p-a);
+ int pb = abs(p-b);
+ int pc = abs(p-c);
+ if (pa <= pb && pa <= pc) return a;
+ if (pb <= pc) return b;
+ return c;
+}
+
+static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
+
+// create the png data from post-deflated data
+static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
+{
+ int bytes = (depth == 16? 2 : 1);
+ stbi__context *s = a->s;
+ stbi__uint32 i,j,stride = x*out_n*bytes;
+ stbi__uint32 img_len, img_width_bytes;
+ int k;
+ int img_n = s->img_n; // copy it into a local for later
+
+ int output_bytes = out_n*bytes;
+ int filter_bytes = img_n*bytes;
+ int width = x;
+
+ STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
+ a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
+ if (!a->out) return stbi__err("outofmem", "Out of memory");
+
+ img_width_bytes = (((img_n * x * depth) + 7) >> 3);
+ img_len = (img_width_bytes + 1) * y;
+ if (s->img_x == x && s->img_y == y) {
+ if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG");
+ } else { // interlaced:
+ if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
+ }
+
+ for (j=0; j < y; ++j) {
+ stbi_uc *cur = a->out + stride*j;
+ stbi_uc *prior = cur - stride;
+ int filter = *raw++;
+
+ if (filter > 4)
+ return stbi__err("invalid filter","Corrupt PNG");
+
+ if (depth < 8) {
+ STBI_ASSERT(img_width_bytes <= x);
+ cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
+ filter_bytes = 1;
+ width = img_width_bytes;
+ }
+
+ // if first row, use special filter that doesn't sample previous row
+ if (j == 0) filter = first_row_filter[filter];
+
+ // handle first byte explicitly
+ for (k=0; k < filter_bytes; ++k) {
+ switch (filter) {
+ case STBI__F_none : cur[k] = raw[k]; break;
+ case STBI__F_sub : cur[k] = raw[k]; break;
+ case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
+ case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
+ case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
+ case STBI__F_avg_first : cur[k] = raw[k]; break;
+ case STBI__F_paeth_first: cur[k] = raw[k]; break;
+ }
+ }
+
+ if (depth == 8) {
+ if (img_n != out_n)
+ cur[img_n] = 255; // first pixel
+ raw += img_n;
+ cur += out_n;
+ prior += out_n;
+ } else if (depth == 16) {
+ if (img_n != out_n) {
+ cur[filter_bytes] = 255; // first pixel top byte
+ cur[filter_bytes+1] = 255; // first pixel bottom byte
+ }
+ raw += filter_bytes;
+ cur += output_bytes;
+ prior += output_bytes;
+ } else {
+ raw += 1;
+ cur += 1;
+ prior += 1;
+ }
+
+ // this is a little gross, so that we don't switch per-pixel or per-component
+ if (depth < 8 || img_n == out_n) {
+ int nk = (width - 1)*filter_bytes;
+ #define STBI__CASE(f) \
+ case f: \
+ for (k=0; k < nk; ++k)
+ switch (filter) {
+ // "none" filter turns into a memcpy here; make that explicit.
+ case STBI__F_none: memcpy(cur, raw, nk); break;
+ STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
+ STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
+ STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
+ STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
+ STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
+ STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
+ }
+ #undef STBI__CASE
+ raw += nk;
+ } else {
+ STBI_ASSERT(img_n+1 == out_n);
+ #define STBI__CASE(f) \
+ case f: \
+ for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
+ for (k=0; k < filter_bytes; ++k)
+ switch (filter) {
+ STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break;
+ STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
+ STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
+ STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
+ STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
+ STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
+ STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
+ }
+ #undef STBI__CASE
+
+ // the loop above sets the high byte of the pixels' alpha, but for
+ // 16 bit png files we also need the low byte set. we'll do that here.
+ if (depth == 16) {
+ cur = a->out + stride*j; // start at the beginning of the row again
+ for (i=0; i < x; ++i,cur+=output_bytes) {
+ cur[filter_bytes+1] = 255;
+ }
+ }
+ }
+ }
+
+ // we make a separate pass to expand bits to pixels; for performance,
+ // this could run two scanlines behind the above code, so it won't
+ // intefere with filtering but will still be in the cache.
+ if (depth < 8) {
+ for (j=0; j < y; ++j) {
+ stbi_uc *cur = a->out + stride*j;
+ stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes;
+ // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
+ // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
+ stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
+
+ // note that the final byte might overshoot and write more data than desired.
+ // we can allocate enough data that this never writes out of memory, but it
+ // could also overwrite the next scanline. can it overwrite non-empty data
+ // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
+ // so we need to explicitly clamp the final ones
+
+ if (depth == 4) {
+ for (k=x*img_n; k >= 2; k-=2, ++in) {
+ *cur++ = scale * ((*in >> 4) );
+ *cur++ = scale * ((*in ) & 0x0f);
+ }
+ if (k > 0) *cur++ = scale * ((*in >> 4) );
+ } else if (depth == 2) {
+ for (k=x*img_n; k >= 4; k-=4, ++in) {
+ *cur++ = scale * ((*in >> 6) );
+ *cur++ = scale * ((*in >> 4) & 0x03);
+ *cur++ = scale * ((*in >> 2) & 0x03);
+ *cur++ = scale * ((*in ) & 0x03);
+ }
+ if (k > 0) *cur++ = scale * ((*in >> 6) );
+ if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
+ if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
+ } else if (depth == 1) {
+ for (k=x*img_n; k >= 8; k-=8, ++in) {
+ *cur++ = scale * ((*in >> 7) );
+ *cur++ = scale * ((*in >> 6) & 0x01);
+ *cur++ = scale * ((*in >> 5) & 0x01);
+ *cur++ = scale * ((*in >> 4) & 0x01);
+ *cur++ = scale * ((*in >> 3) & 0x01);
+ *cur++ = scale * ((*in >> 2) & 0x01);
+ *cur++ = scale * ((*in >> 1) & 0x01);
+ *cur++ = scale * ((*in ) & 0x01);
+ }
+ if (k > 0) *cur++ = scale * ((*in >> 7) );
+ if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
+ if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
+ if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
+ if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
+ if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
+ if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
+ }
+ if (img_n != out_n) {
+ int q;
+ // insert alpha = 255
+ cur = a->out + stride*j;
+ if (img_n == 1) {
+ for (q=x-1; q >= 0; --q) {
+ cur[q*2+1] = 255;
+ cur[q*2+0] = cur[q];
+ }
+ } else {
+ STBI_ASSERT(img_n == 3);
+ for (q=x-1; q >= 0; --q) {
+ cur[q*4+3] = 255;
+ cur[q*4+2] = cur[q*3+2];
+ cur[q*4+1] = cur[q*3+1];
+ cur[q*4+0] = cur[q*3+0];
+ }
+ }
+ }
+ }
+ } else if (depth == 16) {
+ // force the image data from big-endian to platform-native.
+ // this is done in a separate pass due to the decoding relying
+ // on the data being untouched, but could probably be done
+ // per-line during decode if care is taken.
+ stbi_uc *cur = a->out;
+ stbi__uint16 *cur16 = (stbi__uint16*)cur;
+
+ for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
+ *cur16 = (cur[0] << 8) | cur[1];
+ }
+ }
+
+ return 1;
+}
+
+static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
+{
+ int bytes = (depth == 16 ? 2 : 1);
+ int out_bytes = out_n * bytes;
+ stbi_uc *final;
+ int p;
+ if (!interlaced)
+ return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
+
+ // de-interlacing
+ final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
+ for (p=0; p < 7; ++p) {
+ int xorig[] = { 0,4,0,2,0,1,0 };
+ int yorig[] = { 0,0,4,0,2,0,1 };
+ int xspc[] = { 8,8,4,4,2,2,1 };
+ int yspc[] = { 8,8,8,4,4,2,2 };
+ int i,j,x,y;
+ // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
+ x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
+ y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
+ if (x && y) {
+ stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;
+ if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {
+ STBI_FREE(final);
+ return 0;
+ }
+ for (j=0; j < y; ++j) {
+ for (i=0; i < x; ++i) {
+ int out_y = j*yspc[p]+yorig[p];
+ int out_x = i*xspc[p]+xorig[p];
+ memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,
+ a->out + (j*x+i)*out_bytes, out_bytes);
+ }
+ }
+ STBI_FREE(a->out);
+ image_data += img_len;
+ image_data_len -= img_len;
+ }
+ }
+ a->out = final;
+
+ return 1;
+}
+
+static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)
+{
+ stbi__context *s = z->s;
+ stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+ stbi_uc *p = z->out;
+
+ // compute color-based transparency, assuming we've
+ // already got 255 as the alpha value in the output
+ STBI_ASSERT(out_n == 2 || out_n == 4);
+
+ if (out_n == 2) {
+ for (i=0; i < pixel_count; ++i) {
+ p[1] = (p[0] == tc[0] ? 0 : 255);
+ p += 2;
+ }
+ } else {
+ for (i=0; i < pixel_count; ++i) {
+ if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+ p[3] = 0;
+ p += 4;
+ }
+ }
+ return 1;
+}
+
+static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)
+{
+ stbi__context *s = z->s;
+ stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+ stbi__uint16 *p = (stbi__uint16*) z->out;
+
+ // compute color-based transparency, assuming we've
+ // already got 65535 as the alpha value in the output
+ STBI_ASSERT(out_n == 2 || out_n == 4);
+
+ if (out_n == 2) {
+ for (i = 0; i < pixel_count; ++i) {
+ p[1] = (p[0] == tc[0] ? 0 : 65535);
+ p += 2;
+ }
+ } else {
+ for (i = 0; i < pixel_count; ++i) {
+ if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+ p[3] = 0;
+ p += 4;
+ }
+ }
+ return 1;
+}
+
+static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)
+{
+ stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
+ stbi_uc *p, *temp_out, *orig = a->out;
+
+ p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);
+ if (p == NULL) return stbi__err("outofmem", "Out of memory");
+
+ // between here and free(out) below, exitting would leak
+ temp_out = p;
+
+ if (pal_img_n == 3) {
+ for (i=0; i < pixel_count; ++i) {
+ int n = orig[i]*4;
+ p[0] = palette[n ];
+ p[1] = palette[n+1];
+ p[2] = palette[n+2];
+ p += 3;
+ }
+ } else {
+ for (i=0; i < pixel_count; ++i) {
+ int n = orig[i]*4;
+ p[0] = palette[n ];
+ p[1] = palette[n+1];
+ p[2] = palette[n+2];
+ p[3] = palette[n+3];
+ p += 4;
+ }
+ }
+ STBI_FREE(a->out);
+ a->out = temp_out;
+
+ STBI_NOTUSED(len);
+
+ return 1;
+}
+
+static int stbi__unpremultiply_on_load = 0;
+static int stbi__de_iphone_flag = 0;
+
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
+{
+ stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
+}
+
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
+{
+ stbi__de_iphone_flag = flag_true_if_should_convert;
+}
+
+static void stbi__de_iphone(stbi__png *z)
+{
+ stbi__context *s = z->s;
+ stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+ stbi_uc *p = z->out;
+
+ if (s->img_out_n == 3) { // convert bgr to rgb
+ for (i=0; i < pixel_count; ++i) {
+ stbi_uc t = p[0];
+ p[0] = p[2];
+ p[2] = t;
+ p += 3;
+ }
+ } else {
+ STBI_ASSERT(s->img_out_n == 4);
+ if (stbi__unpremultiply_on_load) {
+ // convert bgr to rgb and unpremultiply
+ for (i=0; i < pixel_count; ++i) {
+ stbi_uc a = p[3];
+ stbi_uc t = p[0];
+ if (a) {
+ p[0] = p[2] * 255 / a;
+ p[1] = p[1] * 255 / a;
+ p[2] = t * 255 / a;
+ } else {
+ p[0] = p[2];
+ p[2] = t;
+ }
+ p += 4;
+ }
+ } else {
+ // convert bgr to rgb
+ for (i=0; i < pixel_count; ++i) {
+ stbi_uc t = p[0];
+ p[0] = p[2];
+ p[2] = t;
+ p += 4;
+ }
+ }
+ }
+}
+
+#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
+
+static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
+{
+ stbi_uc palette[1024], pal_img_n=0;
+ stbi_uc has_trans=0, tc[3];
+ stbi__uint16 tc16[3];
+ stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
+ int first=1,k,interlace=0, color=0, is_iphone=0;
+ stbi__context *s = z->s;
+
+ z->expanded = NULL;
+ z->idata = NULL;
+ z->out = NULL;
+
+ if (!stbi__check_png_header(s)) return 0;
+
+ if (scan == STBI__SCAN_type) return 1;
+
+ for (;;) {
+ stbi__pngchunk c = stbi__get_chunk_header(s);
+ switch (c.type) {
+ case STBI__PNG_TYPE('C','g','B','I'):
+ is_iphone = 1;
+ stbi__skip(s, c.length);
+ break;
+ case STBI__PNG_TYPE('I','H','D','R'): {
+ int comp,filter;
+ if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
+ first = 0;
+ if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
+ s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
+ s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
+ z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
+ color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG");
+ if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG");
+ if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
+ comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG");
+ filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG");
+ interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG");
+ if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG");
+ if (!pal_img_n) {
+ s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
+ if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
+ if (scan == STBI__SCAN_header) return 1;
+ } else {
+ // if paletted, then pal_n is our final components, and
+ // img_n is # components to decompress/filter.
+ s->img_n = 1;
+ if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
+ // if SCAN_header, have to scan to see if we have a tRNS
+ }
+ break;
+ }
+
+ case STBI__PNG_TYPE('P','L','T','E'): {
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG");
+ pal_len = c.length / 3;
+ if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG");
+ for (i=0; i < pal_len; ++i) {
+ palette[i*4+0] = stbi__get8(s);
+ palette[i*4+1] = stbi__get8(s);
+ palette[i*4+2] = stbi__get8(s);
+ palette[i*4+3] = 255;
+ }
+ break;
+ }
+
+ case STBI__PNG_TYPE('t','R','N','S'): {
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG");
+ if (pal_img_n) {
+ if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }
+ if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG");
+ if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG");
+ pal_img_n = 4;
+ for (i=0; i < c.length; ++i)
+ palette[i*4+3] = stbi__get8(s);
+ } else {
+ if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
+ if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
+ has_trans = 1;
+ if (z->depth == 16) {
+ for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
+ } else {
+ for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
+ }
+ }
+ break;
+ }
+
+ case STBI__PNG_TYPE('I','D','A','T'): {
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
+ if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
+ if ((int)(ioff + c.length) < (int)ioff) return 0;
+ if (ioff + c.length > idata_limit) {
+ stbi__uint32 idata_limit_old = idata_limit;
+ stbi_uc *p;
+ if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
+ while (ioff + c.length > idata_limit)
+ idata_limit *= 2;
+ STBI_NOTUSED(idata_limit_old);
+ p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
+ z->idata = p;
+ }
+ if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
+ ioff += c.length;
+ break;
+ }
+
+ case STBI__PNG_TYPE('I','E','N','D'): {
+ stbi__uint32 raw_len, bpl;
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (scan != STBI__SCAN_load) return 1;
+ if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG");
+ // initial guess for decoded data size to avoid unnecessary reallocs
+ bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component
+ raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;
+ z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);
+ if (z->expanded == NULL) return 0; // zlib should set error
+ STBI_FREE(z->idata); z->idata = NULL;
+ if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
+ s->img_out_n = s->img_n+1;
+ else
+ s->img_out_n = s->img_n;
+ if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;
+ if (has_trans) {
+ if (z->depth == 16) {
+ if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;
+ } else {
+ if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;
+ }
+ }
+ if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)
+ stbi__de_iphone(z);
+ if (pal_img_n) {
+ // pal_img_n == 3 or 4
+ s->img_n = pal_img_n; // record the actual colors we had
+ s->img_out_n = pal_img_n;
+ if (req_comp >= 3) s->img_out_n = req_comp;
+ if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
+ return 0;
+ }
+ STBI_FREE(z->expanded); z->expanded = NULL;
+ return 1;
+ }
+
+ default:
+ // if critical, fail
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if ((c.type & (1 << 29)) == 0) {
+ #ifndef STBI_NO_FAILURE_STRINGS
+ // not threadsafe
+ static char invalid_chunk[] = "XXXX PNG chunk not known";
+ invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);
+ invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);
+ invalid_chunk[2] = STBI__BYTECAST(c.type >> 8);
+ invalid_chunk[3] = STBI__BYTECAST(c.type >> 0);
+ #endif
+ return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type");
+ }
+ stbi__skip(s, c.length);
+ break;
+ }
+ // end of PNG chunk, read and skip CRC
+ stbi__get32be(s);
+ }
+}
+
+static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)
+{
+ void *result=NULL;
+ if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+ if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
+ if (p->depth < 8)
+ ri->bits_per_channel = 8;
+ else
+ ri->bits_per_channel = p->depth;
+ result = p->out;
+ p->out = NULL;
+ if (req_comp && req_comp != p->s->img_out_n) {
+ if (ri->bits_per_channel == 8)
+ result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+ else
+ result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+ p->s->img_out_n = req_comp;
+ if (result == NULL) return result;
+ }
+ *x = p->s->img_x;
+ *y = p->s->img_y;
+ if (n) *n = p->s->img_n;
+ }
+ STBI_FREE(p->out); p->out = NULL;
+ STBI_FREE(p->expanded); p->expanded = NULL;
+ STBI_FREE(p->idata); p->idata = NULL;
+
+ return result;
+}
+
+static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ stbi__png p;
+ p.s = s;
+ return stbi__do_png(&p, x,y,comp,req_comp, ri);
+}
+
+static int stbi__png_test(stbi__context *s)
+{
+ int r;
+ r = stbi__check_png_header(s);
+ stbi__rewind(s);
+ return r;
+}
+
+static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)
+{
+ if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {
+ stbi__rewind( p->s );
+ return 0;
+ }
+ if (x) *x = p->s->img_x;
+ if (y) *y = p->s->img_y;
+ if (comp) *comp = p->s->img_n;
+ return 1;
+}
+
+static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ stbi__png p;
+ p.s = s;
+ return stbi__png_info_raw(&p, x, y, comp);
+}
+#endif
+
+// Microsoft/Windows BMP image
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_test_raw(stbi__context *s)
+{
+ int r;
+ int sz;
+ if (stbi__get8(s) != 'B') return 0;
+ if (stbi__get8(s) != 'M') return 0;
+ stbi__get32le(s); // discard filesize
+ stbi__get16le(s); // discard reserved
+ stbi__get16le(s); // discard reserved
+ stbi__get32le(s); // discard data offset
+ sz = stbi__get32le(s);
+ r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);
+ return r;
+}
+
+static int stbi__bmp_test(stbi__context *s)
+{
+ int r = stbi__bmp_test_raw(s);
+ stbi__rewind(s);
+ return r;
+}
+
+
+// returns 0..31 for the highest set bit
+static int stbi__high_bit(unsigned int z)
+{
+ int n=0;
+ if (z == 0) return -1;
+ if (z >= 0x10000) n += 16, z >>= 16;
+ if (z >= 0x00100) n += 8, z >>= 8;
+ if (z >= 0x00010) n += 4, z >>= 4;
+ if (z >= 0x00004) n += 2, z >>= 2;
+ if (z >= 0x00002) n += 1, z >>= 1;
+ return n;
+}
+
+static int stbi__bitcount(unsigned int a)
+{
+ a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2
+ a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4
+ a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits
+ a = (a + (a >> 8)); // max 16 per 8 bits
+ a = (a + (a >> 16)); // max 32 per 8 bits
+ return a & 0xff;
+}
+
+static int stbi__shiftsigned(int v, int shift, int bits)
+{
+ int result;
+ int z=0;
+
+ if (shift < 0) v <<= -shift;
+ else v >>= shift;
+ result = v;
+
+ z = bits;
+ while (z < 8) {
+ result += v >> z;
+ z += bits;
+ }
+ return result;
+}
+
+typedef struct
+{
+ int bpp, offset, hsz;
+ unsigned int mr,mg,mb,ma, all_a;
+} stbi__bmp_data;
+
+static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
+{
+ int hsz;
+ if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP");
+ stbi__get32le(s); // discard filesize
+ stbi__get16le(s); // discard reserved
+ stbi__get16le(s); // discard reserved
+ info->offset = stbi__get32le(s);
+ info->hsz = hsz = stbi__get32le(s);
+ info->mr = info->mg = info->mb = info->ma = 0;
+
+ if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
+ if (hsz == 12) {
+ s->img_x = stbi__get16le(s);
+ s->img_y = stbi__get16le(s);
+ } else {
+ s->img_x = stbi__get32le(s);
+ s->img_y = stbi__get32le(s);
+ }
+ if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
+ info->bpp = stbi__get16le(s);
+ if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
+ if (hsz != 12) {
+ int compress = stbi__get32le(s);
+ if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
+ stbi__get32le(s); // discard sizeof
+ stbi__get32le(s); // discard hres
+ stbi__get32le(s); // discard vres
+ stbi__get32le(s); // discard colorsused
+ stbi__get32le(s); // discard max important
+ if (hsz == 40 || hsz == 56) {
+ if (hsz == 56) {
+ stbi__get32le(s);
+ stbi__get32le(s);
+ stbi__get32le(s);
+ stbi__get32le(s);
+ }
+ if (info->bpp == 16 || info->bpp == 32) {
+ if (compress == 0) {
+ if (info->bpp == 32) {
+ info->mr = 0xffu << 16;
+ info->mg = 0xffu << 8;
+ info->mb = 0xffu << 0;
+ info->ma = 0xffu << 24;
+ info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
+ } else {
+ info->mr = 31u << 10;
+ info->mg = 31u << 5;
+ info->mb = 31u << 0;
+ }
+ } else if (compress == 3) {
+ info->mr = stbi__get32le(s);
+ info->mg = stbi__get32le(s);
+ info->mb = stbi__get32le(s);
+ // not documented, but generated by photoshop and handled by mspaint
+ if (info->mr == info->mg && info->mg == info->mb) {
+ // ?!?!?
+ return stbi__errpuc("bad BMP", "bad BMP");
+ }
+ } else
+ return stbi__errpuc("bad BMP", "bad BMP");
+ }
+ } else {
+ int i;
+ if (hsz != 108 && hsz != 124)
+ return stbi__errpuc("bad BMP", "bad BMP");
+ info->mr = stbi__get32le(s);
+ info->mg = stbi__get32le(s);
+ info->mb = stbi__get32le(s);
+ info->ma = stbi__get32le(s);
+ stbi__get32le(s); // discard color space
+ for (i=0; i < 12; ++i)
+ stbi__get32le(s); // discard color space parameters
+ if (hsz == 124) {
+ stbi__get32le(s); // discard rendering intent
+ stbi__get32le(s); // discard offset of profile data
+ stbi__get32le(s); // discard size of profile data
+ stbi__get32le(s); // discard reserved
+ }
+ }
+ }
+ return (void *) 1;
+}
+
+
+static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ stbi_uc *out;
+ unsigned int mr=0,mg=0,mb=0,ma=0, all_a;
+ stbi_uc pal[256][4];
+ int psize=0,i,j,width;
+ int flip_vertically, pad, target;
+ stbi__bmp_data info;
+ STBI_NOTUSED(ri);
+
+ info.all_a = 255;
+ if (stbi__bmp_parse_header(s, &info) == NULL)
+ return NULL; // error code already set
+
+ flip_vertically = ((int) s->img_y) > 0;
+ s->img_y = abs((int) s->img_y);
+
+ mr = info.mr;
+ mg = info.mg;
+ mb = info.mb;
+ ma = info.ma;
+ all_a = info.all_a;
+
+ if (info.hsz == 12) {
+ if (info.bpp < 24)
+ psize = (info.offset - 14 - 24) / 3;
+ } else {
+ if (info.bpp < 16)
+ psize = (info.offset - 14 - info.hsz) >> 2;
+ }
+
+ s->img_n = ma ? 4 : 3;
+ if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
+ target = req_comp;
+ else
+ target = s->img_n; // if they want monochrome, we'll post-convert
+
+ // sanity-check size
+ if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0))
+ return stbi__errpuc("too large", "Corrupt BMP");
+
+ out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0);
+ if (!out) return stbi__errpuc("outofmem", "Out of memory");
+ if (info.bpp < 16) {
+ int z=0;
+ if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); }
+ for (i=0; i < psize; ++i) {
+ pal[i][2] = stbi__get8(s);
+ pal[i][1] = stbi__get8(s);
+ pal[i][0] = stbi__get8(s);
+ if (info.hsz != 12) stbi__get8(s);
+ pal[i][3] = 255;
+ }
+ stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
+ if (info.bpp == 4) width = (s->img_x + 1) >> 1;
+ else if (info.bpp == 8) width = s->img_x;
+ else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
+ pad = (-width)&3;
+ for (j=0; j < (int) s->img_y; ++j) {
+ for (i=0; i < (int) s->img_x; i += 2) {
+ int v=stbi__get8(s),v2=0;
+ if (info.bpp == 4) {
+ v2 = v & 15;
+ v >>= 4;
+ }
+ out[z++] = pal[v][0];
+ out[z++] = pal[v][1];
+ out[z++] = pal[v][2];
+ if (target == 4) out[z++] = 255;
+ if (i+1 == (int) s->img_x) break;
+ v = (info.bpp == 8) ? stbi__get8(s) : v2;
+ out[z++] = pal[v][0];
+ out[z++] = pal[v][1];
+ out[z++] = pal[v][2];
+ if (target == 4) out[z++] = 255;
+ }
+ stbi__skip(s, pad);
+ }
+ } else {
+ int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
+ int z = 0;
+ int easy=0;
+ stbi__skip(s, info.offset - 14 - info.hsz);
+ if (info.bpp == 24) width = 3 * s->img_x;
+ else if (info.bpp == 16) width = 2*s->img_x;
+ else /* bpp = 32 and pad = 0 */ width=0;
+ pad = (-width) & 3;
+ if (info.bpp == 24) {
+ easy = 1;
+ } else if (info.bpp == 32) {
+ if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
+ easy = 2;
+ }
+ if (!easy) {
+ if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
+ // right shift amt to put high bit in position #7
+ rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);
+ gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);
+ bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);
+ ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);
+ }
+ for (j=0; j < (int) s->img_y; ++j) {
+ if (easy) {
+ for (i=0; i < (int) s->img_x; ++i) {
+ unsigned char a;
+ out[z+2] = stbi__get8(s);
+ out[z+1] = stbi__get8(s);
+ out[z+0] = stbi__get8(s);
+ z += 3;
+ a = (easy == 2 ? stbi__get8(s) : 255);
+ all_a |= a;
+ if (target == 4) out[z++] = a;
+ }
+ } else {
+ int bpp = info.bpp;
+ for (i=0; i < (int) s->img_x; ++i) {
+ stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
+ int a;
+ out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
+ out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
+ out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));
+ a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);
+ all_a |= a;
+ if (target == 4) out[z++] = STBI__BYTECAST(a);
+ }
+ }
+ stbi__skip(s, pad);
+ }
+ }
+
+ // if alpha channel is all 0s, replace with all 255s
+ if (target == 4 && all_a == 0)
+ for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4)
+ out[i] = 255;
+
+ if (flip_vertically) {
+ stbi_uc t;
+ for (j=0; j < (int) s->img_y>>1; ++j) {
+ stbi_uc *p1 = out + j *s->img_x*target;
+ stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;
+ for (i=0; i < (int) s->img_x*target; ++i) {
+ t = p1[i], p1[i] = p2[i], p2[i] = t;
+ }
+ }
+ }
+
+ if (req_comp && req_comp != target) {
+ out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);
+ if (out == NULL) return out; // stbi__convert_format frees input on failure
+ }
+
+ *x = s->img_x;
+ *y = s->img_y;
+ if (comp) *comp = s->img_n;
+ return out;
+}
+#endif
+
+// Targa Truevision - TGA
+// by Jonathan Dummer
+#ifndef STBI_NO_TGA
+// returns STBI_rgb or whatever, 0 on error
+static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
+{
+ // only RGB or RGBA (incl. 16bit) or grey allowed
+ if(is_rgb16) *is_rgb16 = 0;
+ switch(bits_per_pixel) {
+ case 8: return STBI_grey;
+ case 16: if(is_grey) return STBI_grey_alpha;
+ // else: fall-through
+ case 15: if(is_rgb16) *is_rgb16 = 1;
+ return STBI_rgb;
+ case 24: // fall-through
+ case 32: return bits_per_pixel/8;
+ default: return 0;
+ }
+}
+
+static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;
+ int sz, tga_colormap_type;
+ stbi__get8(s); // discard Offset
+ tga_colormap_type = stbi__get8(s); // colormap type
+ if( tga_colormap_type > 1 ) {
+ stbi__rewind(s);
+ return 0; // only RGB or indexed allowed
+ }
+ tga_image_type = stbi__get8(s); // image type
+ if ( tga_colormap_type == 1 ) { // colormapped (paletted) image
+ if (tga_image_type != 1 && tga_image_type != 9) {
+ stbi__rewind(s);
+ return 0;
+ }
+ stbi__skip(s,4); // skip index of first colormap entry and number of entries
+ sz = stbi__get8(s); // check bits per palette color entry
+ if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {
+ stbi__rewind(s);
+ return 0;
+ }
+ stbi__skip(s,4); // skip image x and y origin
+ tga_colormap_bpp = sz;
+ } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE
+ if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {
+ stbi__rewind(s);
+ return 0; // only RGB or grey allowed, +/- RLE
+ }
+ stbi__skip(s,9); // skip colormap specification and image x/y origin
+ tga_colormap_bpp = 0;
+ }
+ tga_w = stbi__get16le(s);
+ if( tga_w < 1 ) {
+ stbi__rewind(s);
+ return 0; // test width
+ }
+ tga_h = stbi__get16le(s);
+ if( tga_h < 1 ) {
+ stbi__rewind(s);
+ return 0; // test height
+ }
+ tga_bits_per_pixel = stbi__get8(s); // bits per pixel
+ stbi__get8(s); // ignore alpha bits
+ if (tga_colormap_bpp != 0) {
+ if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {
+ // when using a colormap, tga_bits_per_pixel is the size of the indexes
+ // I don't think anything but 8 or 16bit indexes makes sense
+ stbi__rewind(s);
+ return 0;
+ }
+ tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);
+ } else {
+ tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);
+ }
+ if(!tga_comp) {
+ stbi__rewind(s);
+ return 0;
+ }
+ if (x) *x = tga_w;
+ if (y) *y = tga_h;
+ if (comp) *comp = tga_comp;
+ return 1; // seems to have passed everything
+}
+
+static int stbi__tga_test(stbi__context *s)
+{
+ int res = 0;
+ int sz, tga_color_type;
+ stbi__get8(s); // discard Offset
+ tga_color_type = stbi__get8(s); // color type
+ if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed
+ sz = stbi__get8(s); // image type
+ if ( tga_color_type == 1 ) { // colormapped (paletted) image
+ if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9
+ stbi__skip(s,4); // skip index of first colormap entry and number of entries
+ sz = stbi__get8(s); // check bits per palette color entry
+ if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+ stbi__skip(s,4); // skip image x and y origin
+ } else { // "normal" image w/o colormap
+ if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE
+ stbi__skip(s,9); // skip colormap specification and image x/y origin
+ }
+ if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width
+ if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height
+ sz = stbi__get8(s); // bits per pixel
+ if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index
+ if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+
+ res = 1; // if we got this far, everything's good and we can return 1 instead of 0
+
+errorEnd:
+ stbi__rewind(s);
+ return res;
+}
+
+// read 16bit value and convert to 24bit RGB
+static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)
+{
+ stbi__uint16 px = (stbi__uint16)stbi__get16le(s);
+ stbi__uint16 fiveBitMask = 31;
+ // we have 3 channels with 5bits each
+ int r = (px >> 10) & fiveBitMask;
+ int g = (px >> 5) & fiveBitMask;
+ int b = px & fiveBitMask;
+ // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later
+ out[0] = (stbi_uc)((r * 255)/31);
+ out[1] = (stbi_uc)((g * 255)/31);
+ out[2] = (stbi_uc)((b * 255)/31);
+
+ // some people claim that the most significant bit might be used for alpha
+ // (possibly if an alpha-bit is set in the "image descriptor byte")
+ // but that only made 16bit test images completely translucent..
+ // so let's treat all 15 and 16bit TGAs as RGB with no alpha.
+}
+
+static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ // read in the TGA header stuff
+ int tga_offset = stbi__get8(s);
+ int tga_indexed = stbi__get8(s);
+ int tga_image_type = stbi__get8(s);
+ int tga_is_RLE = 0;
+ int tga_palette_start = stbi__get16le(s);
+ int tga_palette_len = stbi__get16le(s);
+ int tga_palette_bits = stbi__get8(s);
+ int tga_x_origin = stbi__get16le(s);
+ int tga_y_origin = stbi__get16le(s);
+ int tga_width = stbi__get16le(s);
+ int tga_height = stbi__get16le(s);
+ int tga_bits_per_pixel = stbi__get8(s);
+ int tga_comp, tga_rgb16=0;
+ int tga_inverted = stbi__get8(s);
+ // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)
+ // image data
+ unsigned char *tga_data;
+ unsigned char *tga_palette = NULL;
+ int i, j;
+ unsigned char raw_data[4] = {0};
+ int RLE_count = 0;
+ int RLE_repeating = 0;
+ int read_next_pixel = 1;
+ STBI_NOTUSED(ri);
+
+ // do a tiny bit of precessing
+ if ( tga_image_type >= 8 )
+ {
+ tga_image_type -= 8;
+ tga_is_RLE = 1;
+ }
+ tga_inverted = 1 - ((tga_inverted >> 5) & 1);
+
+ // If I'm paletted, then I'll use the number of bits from the palette
+ if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
+ else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);
+
+ if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency
+ return stbi__errpuc("bad format", "Can't find out TGA pixelformat");
+
+ // tga info
+ *x = tga_width;
+ *y = tga_height;
+ if (comp) *comp = tga_comp;
+
+ if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0))
+ return stbi__errpuc("too large", "Corrupt TGA");
+
+ tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);
+ if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
+
+ // skip to the data's starting position (offset usually = 0)
+ stbi__skip(s, tga_offset );
+
+ if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {
+ for (i=0; i < tga_height; ++i) {
+ int row = tga_inverted ? tga_height -i - 1 : i;
+ stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;
+ stbi__getn(s, tga_row, tga_width * tga_comp);
+ }
+ } else {
+ // do I need to load a palette?
+ if ( tga_indexed)
+ {
+ // any data to skip? (offset usually = 0)
+ stbi__skip(s, tga_palette_start );
+ // load the palette
+ tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0);
+ if (!tga_palette) {
+ STBI_FREE(tga_data);
+ return stbi__errpuc("outofmem", "Out of memory");
+ }
+ if (tga_rgb16) {
+ stbi_uc *pal_entry = tga_palette;
+ STBI_ASSERT(tga_comp == STBI_rgb);
+ for (i=0; i < tga_palette_len; ++i) {
+ stbi__tga_read_rgb16(s, pal_entry);
+ pal_entry += tga_comp;
+ }
+ } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {
+ STBI_FREE(tga_data);
+ STBI_FREE(tga_palette);
+ return stbi__errpuc("bad palette", "Corrupt TGA");
+ }
+ }
+ // load the data
+ for (i=0; i < tga_width * tga_height; ++i)
+ {
+ // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?
+ if ( tga_is_RLE )
+ {
+ if ( RLE_count == 0 )
+ {
+ // yep, get the next byte as a RLE command
+ int RLE_cmd = stbi__get8(s);
+ RLE_count = 1 + (RLE_cmd & 127);
+ RLE_repeating = RLE_cmd >> 7;
+ read_next_pixel = 1;
+ } else if ( !RLE_repeating )
+ {
+ read_next_pixel = 1;
+ }
+ } else
+ {
+ read_next_pixel = 1;
+ }
+ // OK, if I need to read a pixel, do it now
+ if ( read_next_pixel )
+ {
+ // load however much data we did have
+ if ( tga_indexed )
+ {
+ // read in index, then perform the lookup
+ int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);
+ if ( pal_idx >= tga_palette_len ) {
+ // invalid index
+ pal_idx = 0;
+ }
+ pal_idx *= tga_comp;
+ for (j = 0; j < tga_comp; ++j) {
+ raw_data[j] = tga_palette[pal_idx+j];
+ }
+ } else if(tga_rgb16) {
+ STBI_ASSERT(tga_comp == STBI_rgb);
+ stbi__tga_read_rgb16(s, raw_data);
+ } else {
+ // read in the data raw
+ for (j = 0; j < tga_comp; ++j) {
+ raw_data[j] = stbi__get8(s);
+ }
+ }
+ // clear the reading flag for the next pixel
+ read_next_pixel = 0;
+ } // end of reading a pixel
+
+ // copy data
+ for (j = 0; j < tga_comp; ++j)
+ tga_data[i*tga_comp+j] = raw_data[j];
+
+ // in case we're in RLE mode, keep counting down
+ --RLE_count;
+ }
+ // do I need to invert the image?
+ if ( tga_inverted )
+ {
+ for (j = 0; j*2 < tga_height; ++j)
+ {
+ int index1 = j * tga_width * tga_comp;
+ int index2 = (tga_height - 1 - j) * tga_width * tga_comp;
+ for (i = tga_width * tga_comp; i > 0; --i)
+ {
+ unsigned char temp = tga_data[index1];
+ tga_data[index1] = tga_data[index2];
+ tga_data[index2] = temp;
+ ++index1;
+ ++index2;
+ }
+ }
+ }
+ // clear my palette, if I had one
+ if ( tga_palette != NULL )
+ {
+ STBI_FREE( tga_palette );
+ }
+ }
+
+ // swap RGB - if the source data was RGB16, it already is in the right order
+ if (tga_comp >= 3 && !tga_rgb16)
+ {
+ unsigned char* tga_pixel = tga_data;
+ for (i=0; i < tga_width * tga_height; ++i)
+ {
+ unsigned char temp = tga_pixel[0];
+ tga_pixel[0] = tga_pixel[2];
+ tga_pixel[2] = temp;
+ tga_pixel += tga_comp;
+ }
+ }
+
+ // convert to target component count
+ if (req_comp && req_comp != tga_comp)
+ tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
+
+ // the things I do to get rid of an error message, and yet keep
+ // Microsoft's C compilers happy... [8^(
+ tga_palette_start = tga_palette_len = tga_palette_bits =
+ tga_x_origin = tga_y_origin = 0;
+ // OK, done
+ return tga_data;
+}
+#endif
+
+// *************************************************************************************************
+// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_test(stbi__context *s)
+{
+ int r = (stbi__get32be(s) == 0x38425053);
+ stbi__rewind(s);
+ return r;
+}
+
+static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount)
+{
+ int count, nleft, len;
+
+ count = 0;
+ while ((nleft = pixelCount - count) > 0) {
+ len = stbi__get8(s);
+ if (len == 128) {
+ // No-op.
+ } else if (len < 128) {
+ // Copy next len+1 bytes literally.
+ len++;
+ if (len > nleft) return 0; // corrupt data
+ count += len;
+ while (len) {
+ *p = stbi__get8(s);
+ p += 4;
+ len--;
+ }
+ } else if (len > 128) {
+ stbi_uc val;
+ // Next -len+1 bytes in the dest are replicated from next source byte.
+ // (Interpret len as a negative 8-bit int.)
+ len = 257 - len;
+ if (len > nleft) return 0; // corrupt data
+ val = stbi__get8(s);
+ count += len;
+ while (len) {
+ *p = val;
+ p += 4;
+ len--;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
+{
+ int pixelCount;
+ int channelCount, compression;
+ int channel, i;
+ int bitdepth;
+ int w,h;
+ stbi_uc *out;
+ STBI_NOTUSED(ri);
+
+ // Check identifier
+ if (stbi__get32be(s) != 0x38425053) // "8BPS"
+ return stbi__errpuc("not PSD", "Corrupt PSD image");
+
+ // Check file type version.
+ if (stbi__get16be(s) != 1)
+ return stbi__errpuc("wrong version", "Unsupported version of PSD image");
+
+ // Skip 6 reserved bytes.
+ stbi__skip(s, 6 );
+
+ // Read the number of channels (R, G, B, A, etc).
+ channelCount = stbi__get16be(s);
+ if (channelCount < 0 || channelCount > 16)
+ return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image");
+
+ // Read the rows and columns of the image.
+ h = stbi__get32be(s);
+ w = stbi__get32be(s);
+
+ // Make sure the depth is 8 bits.
+ bitdepth = stbi__get16be(s);
+ if (bitdepth != 8 && bitdepth != 16)
+ return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit");
+
+ // Make sure the color mode is RGB.
+ // Valid options are:
+ // 0: Bitmap
+ // 1: Grayscale
+ // 2: Indexed color
+ // 3: RGB color
+ // 4: CMYK color
+ // 7: Multichannel
+ // 8: Duotone
+ // 9: Lab color
+ if (stbi__get16be(s) != 3)
+ return stbi__errpuc("wrong color format", "PSD is not in RGB color format");
+
+ // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.)
+ stbi__skip(s,stbi__get32be(s) );
+
+ // Skip the image resources. (resolution, pen tool paths, etc)
+ stbi__skip(s, stbi__get32be(s) );
+
+ // Skip the reserved data.
+ stbi__skip(s, stbi__get32be(s) );
+
+ // Find out if the data is compressed.
+ // Known values:
+ // 0: no compression
+ // 1: RLE compressed
+ compression = stbi__get16be(s);
+ if (compression > 1)
+ return stbi__errpuc("bad compression", "PSD has an unknown compression format");
+
+ // Check size
+ if (!stbi__mad3sizes_valid(4, w, h, 0))
+ return stbi__errpuc("too large", "Corrupt PSD");
+
+ // Create the destination image.
+
+ if (!compression && bitdepth == 16 && bpc == 16) {
+ out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0);
+ ri->bits_per_channel = 16;
+ } else
+ out = (stbi_uc *) stbi__malloc(4 * w*h);
+
+ if (!out) return stbi__errpuc("outofmem", "Out of memory");
+ pixelCount = w*h;
+
+ // Initialize the data to zero.
+ //memset( out, 0, pixelCount * 4 );
+
+ // Finally, the image data.
+ if (compression) {
+ // RLE as used by .PSD and .TIFF
+ // Loop until you get the number of unpacked bytes you are expecting:
+ // Read the next source byte into n.
+ // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
+ // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.
+ // Else if n is 128, noop.
+ // Endloop
+
+ // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data,
+ // which we're going to just skip.
+ stbi__skip(s, h * channelCount * 2 );
+
+ // Read the RLE data by channel.
+ for (channel = 0; channel < 4; channel++) {
+ stbi_uc *p;
+
+ p = out+channel;
+ if (channel >= channelCount) {
+ // Fill this channel with default data.
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = (channel == 3 ? 255 : 0);
+ } else {
+ // Read the RLE data.
+ if (!stbi__psd_decode_rle(s, p, pixelCount)) {
+ STBI_FREE(out);
+ return stbi__errpuc("corrupt", "bad RLE data");
+ }
+ }
+ }
+
+ } else {
+ // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...)
+ // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image.
+
+ // Read the data by channel.
+ for (channel = 0; channel < 4; channel++) {
+ if (channel >= channelCount) {
+ // Fill this channel with default data.
+ if (bitdepth == 16 && bpc == 16) {
+ stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
+ stbi__uint16 val = channel == 3 ? 65535 : 0;
+ for (i = 0; i < pixelCount; i++, q += 4)
+ *q = val;
+ } else {
+ stbi_uc *p = out+channel;
+ stbi_uc val = channel == 3 ? 255 : 0;
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = val;
+ }
+ } else {
+ if (ri->bits_per_channel == 16) { // output bpc
+ stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
+ for (i = 0; i < pixelCount; i++, q += 4)
+ *q = (stbi__uint16) stbi__get16be(s);
+ } else {
+ stbi_uc *p = out+channel;
+ if (bitdepth == 16) { // input bpc
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = (stbi_uc) (stbi__get16be(s) >> 8);
+ } else {
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = stbi__get8(s);
+ }
+ }
+ }
+ }
+ }
+
+ // remove weird white matte from PSD
+ if (channelCount >= 4) {
+ if (ri->bits_per_channel == 16) {
+ for (i=0; i < w*h; ++i) {
+ stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i;
+ if (pixel[3] != 0 && pixel[3] != 65535) {
+ float a = pixel[3] / 65535.0f;
+ float ra = 1.0f / a;
+ float inv_a = 65535.0f * (1 - ra);
+ pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a);
+ pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a);
+ pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a);
+ }
+ }
+ } else {
+ for (i=0; i < w*h; ++i) {
+ unsigned char *pixel = out + 4*i;
+ if (pixel[3] != 0 && pixel[3] != 255) {
+ float a = pixel[3] / 255.0f;
+ float ra = 1.0f / a;
+ float inv_a = 255.0f * (1 - ra);
+ pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);
+ pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);
+ pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);
+ }
+ }
+ }
+ }
+
+ // convert to desired output format
+ if (req_comp && req_comp != 4) {
+ if (ri->bits_per_channel == 16)
+ out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h);
+ else
+ out = stbi__convert_format(out, 4, req_comp, w, h);
+ if (out == NULL) return out; // stbi__convert_format frees input on failure
+ }
+
+ if (comp) *comp = 4;
+ *y = h;
+ *x = w;
+
+ return out;
+}
+#endif
+
+// *************************************************************************************************
+// Softimage PIC loader
+// by Tom Seddon
+//
+// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format
+// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_is4(stbi__context *s,const char *str)
+{
+ int i;
+ for (i=0; i<4; ++i)
+ if (stbi__get8(s) != (stbi_uc)str[i])
+ return 0;
+
+ return 1;
+}
+
+static int stbi__pic_test_core(stbi__context *s)
+{
+ int i;
+
+ if (!stbi__pic_is4(s,"\x53\x80\xF6\x34"))
+ return 0;
+
+ for(i=0;i<84;++i)
+ stbi__get8(s);
+
+ if (!stbi__pic_is4(s,"PICT"))
+ return 0;
+
+ return 1;
+}
+
+typedef struct
+{
+ stbi_uc size,type,channel;
+} stbi__pic_packet;
+
+static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)
+{
+ int mask=0x80, i;
+
+ for (i=0; i<4; ++i, mask>>=1) {
+ if (channel & mask) {
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short");
+ dest[i]=stbi__get8(s);
+ }
+ }
+
+ return dest;
+}
+
+static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)
+{
+ int mask=0x80,i;
+
+ for (i=0;i<4; ++i, mask>>=1)
+ if (channel&mask)
+ dest[i]=src[i];
+}
+
+static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)
+{
+ int act_comp=0,num_packets=0,y,chained;
+ stbi__pic_packet packets[10];
+
+ // this will (should...) cater for even some bizarre stuff like having data
+ // for the same channel in multiple packets.
+ do {
+ stbi__pic_packet *packet;
+
+ if (num_packets==sizeof(packets)/sizeof(packets[0]))
+ return stbi__errpuc("bad format","too many packets");
+
+ packet = &packets[num_packets++];
+
+ chained = stbi__get8(s);
+ packet->size = stbi__get8(s);
+ packet->type = stbi__get8(s);
+ packet->channel = stbi__get8(s);
+
+ act_comp |= packet->channel;
+
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)");
+ if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp");
+ } while (chained);
+
+ *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?
+
+ for(y=0; y<height; ++y) {
+ int packet_idx;
+
+ for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {
+ stbi__pic_packet *packet = &packets[packet_idx];
+ stbi_uc *dest = result+y*width*4;
+
+ switch (packet->type) {
+ default:
+ return stbi__errpuc("bad format","packet has bad compression type");
+
+ case 0: {//uncompressed
+ int x;
+
+ for(x=0;x<width;++x, dest+=4)
+ if (!stbi__readval(s,packet->channel,dest))
+ return 0;
+ break;
+ }
+
+ case 1://Pure RLE
+ {
+ int left=width, i;
+
+ while (left>0) {
+ stbi_uc count,value[4];
+
+ count=stbi__get8(s);
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)");
+
+ if (count > left)
+ count = (stbi_uc) left;
+
+ if (!stbi__readval(s,packet->channel,value)) return 0;
+
+ for(i=0; i<count; ++i,dest+=4)
+ stbi__copyval(packet->channel,dest,value);
+ left -= count;
+ }
+ }
+ break;
+
+ case 2: {//Mixed RLE
+ int left=width;
+ while (left>0) {
+ int count = stbi__get8(s), i;
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)");
+
+ if (count >= 128) { // Repeated
+ stbi_uc value[4];
+
+ if (count==128)
+ count = stbi__get16be(s);
+ else
+ count -= 127;
+ if (count > left)
+ return stbi__errpuc("bad file","scanline overrun");
+
+ if (!stbi__readval(s,packet->channel,value))
+ return 0;
+
+ for(i=0;i<count;++i, dest += 4)
+ stbi__copyval(packet->channel,dest,value);
+ } else { // Raw
+ ++count;
+ if (count>left) return stbi__errpuc("bad file","scanline overrun");
+
+ for(i=0;i<count;++i, dest+=4)
+ if (!stbi__readval(s,packet->channel,dest))
+ return 0;
+ }
+ left-=count;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)
+{
+ stbi_uc *result;
+ int i, x,y;
+ STBI_NOTUSED(ri);
+
+ for (i=0; i<92; ++i)
+ stbi__get8(s);
+
+ x = stbi__get16be(s);
+ y = stbi__get16be(s);
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)");
+ if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode");
+
+ stbi__get32be(s); //skip `ratio'
+ stbi__get16be(s); //skip `fields'
+ stbi__get16be(s); //skip `pad'
+
+ // intermediate buffer is RGBA
+ result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);
+ memset(result, 0xff, x*y*4);
+
+ if (!stbi__pic_load_core(s,x,y,comp, result)) {
+ STBI_FREE(result);
+ result=0;
+ }
+ *px = x;
+ *py = y;
+ if (req_comp == 0) req_comp = *comp;
+ result=stbi__convert_format(result,4,req_comp,x,y);
+
+ return result;
+}
+
+static int stbi__pic_test(stbi__context *s)
+{
+ int r = stbi__pic_test_core(s);
+ stbi__rewind(s);
+ return r;
+}
+#endif
+
+// *************************************************************************************************
+// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb
+
+#ifndef STBI_NO_GIF
+typedef struct
+{
+ stbi__int16 prefix;
+ stbi_uc first;
+ stbi_uc suffix;
+} stbi__gif_lzw;
+
+typedef struct
+{
+ int w,h;
+ stbi_uc *out, *old_out; // output buffer (always 4 components)
+ int flags, bgindex, ratio, transparent, eflags, delay;
+ stbi_uc pal[256][4];
+ stbi_uc lpal[256][4];
+ stbi__gif_lzw codes[4096];
+ stbi_uc *color_table;
+ int parse, step;
+ int lflags;
+ int start_x, start_y;
+ int max_x, max_y;
+ int cur_x, cur_y;
+ int line_size;
+} stbi__gif;
+
+static int stbi__gif_test_raw(stbi__context *s)
+{
+ int sz;
+ if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;
+ sz = stbi__get8(s);
+ if (sz != '9' && sz != '7') return 0;
+ if (stbi__get8(s) != 'a') return 0;
+ return 1;
+}
+
+static int stbi__gif_test(stbi__context *s)
+{
+ int r = stbi__gif_test_raw(s);
+ stbi__rewind(s);
+ return r;
+}
+
+static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)
+{
+ int i;
+ for (i=0; i < num_entries; ++i) {
+ pal[i][2] = stbi__get8(s);
+ pal[i][1] = stbi__get8(s);
+ pal[i][0] = stbi__get8(s);
+ pal[i][3] = transp == i ? 0 : 255;
+ }
+}
+
+static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)
+{
+ stbi_uc version;
+ if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')
+ return stbi__err("not GIF", "Corrupt GIF");
+
+ version = stbi__get8(s);
+ if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF");
+ if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF");
+
+ stbi__g_failure_reason = "";
+ g->w = stbi__get16le(s);
+ g->h = stbi__get16le(s);
+ g->flags = stbi__get8(s);
+ g->bgindex = stbi__get8(s);
+ g->ratio = stbi__get8(s);
+ g->transparent = -1;
+
+ if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments
+
+ if (is_info) return 1;
+
+ if (g->flags & 0x80)
+ stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);
+
+ return 1;
+}
+
+static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
+{
+ stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
+ if (!stbi__gif_header(s, g, comp, 1)) {
+ STBI_FREE(g);
+ stbi__rewind( s );
+ return 0;
+ }
+ if (x) *x = g->w;
+ if (y) *y = g->h;
+ STBI_FREE(g);
+ return 1;
+}
+
+static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
+{
+ stbi_uc *p, *c;
+
+ // recurse to decode the prefixes, since the linked-list is backwards,
+ // and working backwards through an interleaved image would be nasty
+ if (g->codes[code].prefix >= 0)
+ stbi__out_gif_code(g, g->codes[code].prefix);
+
+ if (g->cur_y >= g->max_y) return;
+
+ p = &g->out[g->cur_x + g->cur_y];
+ c = &g->color_table[g->codes[code].suffix * 4];
+
+ if (c[3] >= 128) {
+ p[0] = c[2];
+ p[1] = c[1];
+ p[2] = c[0];
+ p[3] = c[3];
+ }
+ g->cur_x += 4;
+
+ if (g->cur_x >= g->max_x) {
+ g->cur_x = g->start_x;
+ g->cur_y += g->step;
+
+ while (g->cur_y >= g->max_y && g->parse > 0) {
+ g->step = (1 << g->parse) * g->line_size;
+ g->cur_y = g->start_y + (g->step >> 1);
+ --g->parse;
+ }
+ }
+}
+
+static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
+{
+ stbi_uc lzw_cs;
+ stbi__int32 len, init_code;
+ stbi__uint32 first;
+ stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;
+ stbi__gif_lzw *p;
+
+ lzw_cs = stbi__get8(s);
+ if (lzw_cs > 12) return NULL;
+ clear = 1 << lzw_cs;
+ first = 1;
+ codesize = lzw_cs + 1;
+ codemask = (1 << codesize) - 1;
+ bits = 0;
+ valid_bits = 0;
+ for (init_code = 0; init_code < clear; init_code++) {
+ g->codes[init_code].prefix = -1;
+ g->codes[init_code].first = (stbi_uc) init_code;
+ g->codes[init_code].suffix = (stbi_uc) init_code;
+ }
+
+ // support no starting clear code
+ avail = clear+2;
+ oldcode = -1;
+
+ len = 0;
+ for(;;) {
+ if (valid_bits < codesize) {
+ if (len == 0) {
+ len = stbi__get8(s); // start new block
+ if (len == 0)
+ return g->out;
+ }
+ --len;
+ bits |= (stbi__int32) stbi__get8(s) << valid_bits;
+ valid_bits += 8;
+ } else {
+ stbi__int32 code = bits & codemask;
+ bits >>= codesize;
+ valid_bits -= codesize;
+ // @OPTIMIZE: is there some way we can accelerate the non-clear path?
+ if (code == clear) { // clear code
+ codesize = lzw_cs + 1;
+ codemask = (1 << codesize) - 1;
+ avail = clear + 2;
+ oldcode = -1;
+ first = 0;
+ } else if (code == clear + 1) { // end of stream code
+ stbi__skip(s, len);
+ while ((len = stbi__get8(s)) > 0)
+ stbi__skip(s,len);
+ return g->out;
+ } else if (code <= avail) {
+ if (first) return stbi__errpuc("no clear code", "Corrupt GIF");
+
+ if (oldcode >= 0) {
+ p = &g->codes[avail++];
+ if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF");
+ p->prefix = (stbi__int16) oldcode;
+ p->first = g->codes[oldcode].first;
+ p->suffix = (code == avail) ? p->first : g->codes[code].first;
+ } else if (code == avail)
+ return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+
+ stbi__out_gif_code(g, (stbi__uint16) code);
+
+ if ((avail & codemask) == 0 && avail <= 0x0FFF) {
+ codesize++;
+ codemask = (1 << codesize) - 1;
+ }
+
+ oldcode = code;
+ } else {
+ return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+ }
+ }
+ }
+}
+
+static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1)
+{
+ int x, y;
+ stbi_uc *c = g->pal[g->bgindex];
+ for (y = y0; y < y1; y += 4 * g->w) {
+ for (x = x0; x < x1; x += 4) {
+ stbi_uc *p = &g->out[y + x];
+ p[0] = c[2];
+ p[1] = c[1];
+ p[2] = c[0];
+ p[3] = 0;
+ }
+ }
+}
+
+// this function is designed to support animated gifs, although stb_image doesn't support it
+static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp)
+{
+ int i;
+ stbi_uc *prev_out = 0;
+
+ if (g->out == 0 && !stbi__gif_header(s, g, comp,0))
+ return 0; // stbi__g_failure_reason set by stbi__gif_header
+
+ if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0))
+ return stbi__errpuc("too large", "GIF too large");
+
+ prev_out = g->out;
+ g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0);
+ if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
+
+ switch ((g->eflags & 0x1C) >> 2) {
+ case 0: // unspecified (also always used on 1st frame)
+ stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h);
+ break;
+ case 1: // do not dispose
+ if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
+ g->old_out = prev_out;
+ break;
+ case 2: // dispose to background
+ if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
+ stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y);
+ break;
+ case 3: // dispose to previous
+ if (g->old_out) {
+ for (i = g->start_y; i < g->max_y; i += 4 * g->w)
+ memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x);
+ }
+ break;
+ }
+
+ for (;;) {
+ switch (stbi__get8(s)) {
+ case 0x2C: /* Image Descriptor */
+ {
+ int prev_trans = -1;
+ stbi__int32 x, y, w, h;
+ stbi_uc *o;
+
+ x = stbi__get16le(s);
+ y = stbi__get16le(s);
+ w = stbi__get16le(s);
+ h = stbi__get16le(s);
+ if (((x + w) > (g->w)) || ((y + h) > (g->h)))
+ return stbi__errpuc("bad Image Descriptor", "Corrupt GIF");
+
+ g->line_size = g->w * 4;
+ g->start_x = x * 4;
+ g->start_y = y * g->line_size;
+ g->max_x = g->start_x + w * 4;
+ g->max_y = g->start_y + h * g->line_size;
+ g->cur_x = g->start_x;
+ g->cur_y = g->start_y;
+
+ g->lflags = stbi__get8(s);
+
+ if (g->lflags & 0x40) {
+ g->step = 8 * g->line_size; // first interlaced spacing
+ g->parse = 3;
+ } else {
+ g->step = g->line_size;
+ g->parse = 0;
+ }
+
+ if (g->lflags & 0x80) {
+ stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
+ g->color_table = (stbi_uc *) g->lpal;
+ } else if (g->flags & 0x80) {
+ if (g->transparent >= 0 && (g->eflags & 0x01)) {
+ prev_trans = g->pal[g->transparent][3];
+ g->pal[g->transparent][3] = 0;
+ }
+ g->color_table = (stbi_uc *) g->pal;
+ } else
+ return stbi__errpuc("missing color table", "Corrupt GIF");
+
+ o = stbi__process_gif_raster(s, g);
+ if (o == NULL) return NULL;
+
+ if (prev_trans != -1)
+ g->pal[g->transparent][3] = (stbi_uc) prev_trans;
+
+ return o;
+ }
+
+ case 0x21: // Comment Extension.
+ {
+ int len;
+ if (stbi__get8(s) == 0xF9) { // Graphic Control Extension.
+ len = stbi__get8(s);
+ if (len == 4) {
+ g->eflags = stbi__get8(s);
+ g->delay = stbi__get16le(s);
+ g->transparent = stbi__get8(s);
+ } else {
+ stbi__skip(s, len);
+ break;
+ }
+ }
+ while ((len = stbi__get8(s)) != 0)
+ stbi__skip(s, len);
+ break;
+ }
+
+ case 0x3B: // gif stream termination code
+ return (stbi_uc *) s; // using '1' causes warning on some compilers
+
+ default:
+ return stbi__errpuc("unknown code", "Corrupt GIF");
+ }
+ }
+
+ STBI_NOTUSED(req_comp);
+}
+
+static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ stbi_uc *u = 0;
+ stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
+ memset(g, 0, sizeof(*g));
+ STBI_NOTUSED(ri);
+
+ u = stbi__gif_load_next(s, g, comp, req_comp);
+ if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
+ if (u) {
+ *x = g->w;
+ *y = g->h;
+ if (req_comp && req_comp != 4)
+ u = stbi__convert_format(u, 4, req_comp, g->w, g->h);
+ }
+ else if (g->out)
+ STBI_FREE(g->out);
+ STBI_FREE(g);
+ return u;
+}
+
+static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ return stbi__gif_info_raw(s,x,y,comp);
+}
+#endif
+
+// *************************************************************************************************
+// Radiance RGBE HDR loader
+// originally by Nicolas Schulz
+#ifndef STBI_NO_HDR
+static int stbi__hdr_test_core(stbi__context *s, const char *signature)
+{
+ int i;
+ for (i=0; signature[i]; ++i)
+ if (stbi__get8(s) != signature[i])
+ return 0;
+ stbi__rewind(s);
+ return 1;
+}
+
+static int stbi__hdr_test(stbi__context* s)
+{
+ int r = stbi__hdr_test_core(s, "#?RADIANCE\n");
+ stbi__rewind(s);
+ if(!r) {
+ r = stbi__hdr_test_core(s, "#?RGBE\n");
+ stbi__rewind(s);
+ }
+ return r;
+}
+
+#define STBI__HDR_BUFLEN 1024
+static char *stbi__hdr_gettoken(stbi__context *z, char *buffer)
+{
+ int len=0;
+ char c = '\0';
+
+ c = (char) stbi__get8(z);
+
+ while (!stbi__at_eof(z) && c != '\n') {
+ buffer[len++] = c;
+ if (len == STBI__HDR_BUFLEN-1) {
+ // flush to end of line
+ while (!stbi__at_eof(z) && stbi__get8(z) != '\n')
+ ;
+ break;
+ }
+ c = (char) stbi__get8(z);
+ }
+
+ buffer[len] = 0;
+ return buffer;
+}
+
+static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)
+{
+ if ( input[3] != 0 ) {
+ float f1;
+ // Exponent
+ f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));
+ if (req_comp <= 2)
+ output[0] = (input[0] + input[1] + input[2]) * f1 / 3;
+ else {
+ output[0] = input[0] * f1;
+ output[1] = input[1] * f1;
+ output[2] = input[2] * f1;
+ }
+ if (req_comp == 2) output[1] = 1;
+ if (req_comp == 4) output[3] = 1;
+ } else {
+ switch (req_comp) {
+ case 4: output[3] = 1; /* fallthrough */
+ case 3: output[0] = output[1] = output[2] = 0;
+ break;
+ case 2: output[1] = 1; /* fallthrough */
+ case 1: output[0] = 0;
+ break;
+ }
+ }
+}
+
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ char buffer[STBI__HDR_BUFLEN];
+ char *token;
+ int valid = 0;
+ int width, height;
+ stbi_uc *scanline;
+ float *hdr_data;
+ int len;
+ unsigned char count, value;
+ int i, j, k, c1,c2, z;
+ const char *headerToken;
+ STBI_NOTUSED(ri);
+
+ // Check identifier
+ headerToken = stbi__hdr_gettoken(s,buffer);
+ if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0)
+ return stbi__errpf("not HDR", "Corrupt HDR image");
+
+ // Parse header
+ for(;;) {
+ token = stbi__hdr_gettoken(s,buffer);
+ if (token[0] == 0) break;
+ if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+ }
+
+ if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format");
+
+ // Parse width and height
+ // can't use sscanf() if we're not using stdio!
+ token = stbi__hdr_gettoken(s,buffer);
+ if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+ token += 3;
+ height = (int) strtol(token, &token, 10);
+ while (*token == ' ') ++token;
+ if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+ token += 3;
+ width = (int) strtol(token, NULL, 10);
+
+ *x = width;
+ *y = height;
+
+ if (comp) *comp = 3;
+ if (req_comp == 0) req_comp = 3;
+
+ if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0))
+ return stbi__errpf("too large", "HDR image is too large");
+
+ // Read data
+ hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);
+ if (!hdr_data)
+ return stbi__errpf("outofmem", "Out of memory");
+
+ // Load image data
+ // image data is stored as some number of sca
+ if ( width < 8 || width >= 32768) {
+ // Read flat data
+ for (j=0; j < height; ++j) {
+ for (i=0; i < width; ++i) {
+ stbi_uc rgbe[4];
+ main_decode_loop:
+ stbi__getn(s, rgbe, 4);
+ stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);
+ }
+ }
+ } else {
+ // Read RLE-encoded data
+ scanline = NULL;
+
+ for (j = 0; j < height; ++j) {
+ c1 = stbi__get8(s);
+ c2 = stbi__get8(s);
+ len = stbi__get8(s);
+ if (c1 != 2 || c2 != 2 || (len & 0x80)) {
+ // not run-length encoded, so we have to actually use THIS data as a decoded
+ // pixel (note this can't be a valid pixel--one of RGB must be >= 128)
+ stbi_uc rgbe[4];
+ rgbe[0] = (stbi_uc) c1;
+ rgbe[1] = (stbi_uc) c2;
+ rgbe[2] = (stbi_uc) len;
+ rgbe[3] = (stbi_uc) stbi__get8(s);
+ stbi__hdr_convert(hdr_data, rgbe, req_comp);
+ i = 1;
+ j = 0;
+ STBI_FREE(scanline);
+ goto main_decode_loop; // yes, this makes no sense
+ }
+ len <<= 8;
+ len |= stbi__get8(s);
+ if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); }
+ if (scanline == NULL) {
+ scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0);
+ if (!scanline) {
+ STBI_FREE(hdr_data);
+ return stbi__errpf("outofmem", "Out of memory");
+ }
+ }
+
+ for (k = 0; k < 4; ++k) {
+ int nleft;
+ i = 0;
+ while ((nleft = width - i) > 0) {
+ count = stbi__get8(s);
+ if (count > 128) {
+ // Run
+ value = stbi__get8(s);
+ count -= 128;
+ if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
+ for (z = 0; z < count; ++z)
+ scanline[i++ * 4 + k] = value;
+ } else {
+ // Dump
+ if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
+ for (z = 0; z < count; ++z)
+ scanline[i++ * 4 + k] = stbi__get8(s);
+ }
+ }
+ }
+ for (i=0; i < width; ++i)
+ stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);
+ }
+ if (scanline)
+ STBI_FREE(scanline);
+ }
+
+ return hdr_data;
+}
+
+static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ char buffer[STBI__HDR_BUFLEN];
+ char *token;
+ int valid = 0;
+
+ if (stbi__hdr_test(s) == 0) {
+ stbi__rewind( s );
+ return 0;
+ }
+
+ for(;;) {
+ token = stbi__hdr_gettoken(s,buffer);
+ if (token[0] == 0) break;
+ if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+ }
+
+ if (!valid) {
+ stbi__rewind( s );
+ return 0;
+ }
+ token = stbi__hdr_gettoken(s,buffer);
+ if (strncmp(token, "-Y ", 3)) {
+ stbi__rewind( s );
+ return 0;
+ }
+ token += 3;
+ *y = (int) strtol(token, &token, 10);
+ while (*token == ' ') ++token;
+ if (strncmp(token, "+X ", 3)) {
+ stbi__rewind( s );
+ return 0;
+ }
+ token += 3;
+ *x = (int) strtol(token, NULL, 10);
+ *comp = 3;
+ return 1;
+}
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ void *p;
+ stbi__bmp_data info;
+
+ info.all_a = 255;
+ p = stbi__bmp_parse_header(s, &info);
+ stbi__rewind( s );
+ if (p == NULL)
+ return 0;
+ *x = s->img_x;
+ *y = s->img_y;
+ *comp = info.ma ? 4 : 3;
+ return 1;
+}
+#endif
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int channelCount;
+ if (stbi__get32be(s) != 0x38425053) {
+ stbi__rewind( s );
+ return 0;
+ }
+ if (stbi__get16be(s) != 1) {
+ stbi__rewind( s );
+ return 0;
+ }
+ stbi__skip(s, 6);
+ channelCount = stbi__get16be(s);
+ if (channelCount < 0 || channelCount > 16) {
+ stbi__rewind( s );
+ return 0;
+ }
+ *y = stbi__get32be(s);
+ *x = stbi__get32be(s);
+ if (stbi__get16be(s) != 8) {
+ stbi__rewind( s );
+ return 0;
+ }
+ if (stbi__get16be(s) != 3) {
+ stbi__rewind( s );
+ return 0;
+ }
+ *comp = 4;
+ return 1;
+}
+#endif
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int act_comp=0,num_packets=0,chained;
+ stbi__pic_packet packets[10];
+
+ if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) {
+ stbi__rewind(s);
+ return 0;
+ }
+
+ stbi__skip(s, 88);
+
+ *x = stbi__get16be(s);
+ *y = stbi__get16be(s);
+ if (stbi__at_eof(s)) {
+ stbi__rewind( s);
+ return 0;
+ }
+ if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {
+ stbi__rewind( s );
+ return 0;
+ }
+
+ stbi__skip(s, 8);
+
+ do {
+ stbi__pic_packet *packet;
+
+ if (num_packets==sizeof(packets)/sizeof(packets[0]))
+ return 0;
+
+ packet = &packets[num_packets++];
+ chained = stbi__get8(s);
+ packet->size = stbi__get8(s);
+ packet->type = stbi__get8(s);
+ packet->channel = stbi__get8(s);
+ act_comp |= packet->channel;
+
+ if (stbi__at_eof(s)) {
+ stbi__rewind( s );
+ return 0;
+ }
+ if (packet->size != 8) {
+ stbi__rewind( s );
+ return 0;
+ }
+ } while (chained);
+
+ *comp = (act_comp & 0x10 ? 4 : 3);
+
+ return 1;
+}
+#endif
+
+// *************************************************************************************************
+// Portable Gray Map and Portable Pixel Map loader
+// by Ken Miller
+//
+// PGM: http://netpbm.sourceforge.net/doc/pgm.html
+// PPM: http://netpbm.sourceforge.net/doc/ppm.html
+//
+// Known limitations:
+// Does not support comments in the header section
+// Does not support ASCII image data (formats P2 and P3)
+// Does not support 16-bit-per-channel
+
+#ifndef STBI_NO_PNM
+
+static int stbi__pnm_test(stbi__context *s)
+{
+ char p, t;
+ p = (char) stbi__get8(s);
+ t = (char) stbi__get8(s);
+ if (p != 'P' || (t != '5' && t != '6')) {
+ stbi__rewind( s );
+ return 0;
+ }
+ return 1;
+}
+
+static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ stbi_uc *out;
+ STBI_NOTUSED(ri);
+
+ if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))
+ return 0;
+
+ *x = s->img_x;
+ *y = s->img_y;
+ *comp = s->img_n;
+
+ if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0))
+ return stbi__errpuc("too large", "PNM too large");
+
+ out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0);
+ if (!out) return stbi__errpuc("outofmem", "Out of memory");
+ stbi__getn(s, out, s->img_n * s->img_x * s->img_y);
+
+ if (req_comp && req_comp != s->img_n) {
+ out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);
+ if (out == NULL) return out; // stbi__convert_format frees input on failure
+ }
+ return out;
+}
+
+static int stbi__pnm_isspace(char c)
+{
+ return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
+}
+
+static void stbi__pnm_skip_whitespace(stbi__context *s, char *c)
+{
+ for (;;) {
+ while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))
+ *c = (char) stbi__get8(s);
+
+ if (stbi__at_eof(s) || *c != '#')
+ break;
+
+ while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' )
+ *c = (char) stbi__get8(s);
+ }
+}
+
+static int stbi__pnm_isdigit(char c)
+{
+ return c >= '0' && c <= '9';
+}
+
+static int stbi__pnm_getinteger(stbi__context *s, char *c)
+{
+ int value = 0;
+
+ while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {
+ value = value*10 + (*c - '0');
+ *c = (char) stbi__get8(s);
+ }
+
+ return value;
+}
+
+static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int maxv;
+ char c, p, t;
+
+ stbi__rewind( s );
+
+ // Get identifier
+ p = (char) stbi__get8(s);
+ t = (char) stbi__get8(s);
+ if (p != 'P' || (t != '5' && t != '6')) {
+ stbi__rewind( s );
+ return 0;
+ }
+
+ *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm
+
+ c = (char) stbi__get8(s);
+ stbi__pnm_skip_whitespace(s, &c);
+
+ *x = stbi__pnm_getinteger(s, &c); // read width
+ stbi__pnm_skip_whitespace(s, &c);
+
+ *y = stbi__pnm_getinteger(s, &c); // read height
+ stbi__pnm_skip_whitespace(s, &c);
+
+ maxv = stbi__pnm_getinteger(s, &c); // read max value
+
+ if (maxv > 255)
+ return stbi__err("max value > 255", "PPM image not 8-bit");
+ else
+ return 1;
+}
+#endif
+
+static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
+{
+ #ifndef STBI_NO_JPEG
+ if (stbi__jpeg_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PNG
+ if (stbi__png_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_GIF
+ if (stbi__gif_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_BMP
+ if (stbi__bmp_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PSD
+ if (stbi__psd_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PIC
+ if (stbi__pic_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PNM
+ if (stbi__pnm_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_HDR
+ if (stbi__hdr_info(s, x, y, comp)) return 1;
+ #endif
+
+ // test tga last because it's a crappy test!
+ #ifndef STBI_NO_TGA
+ if (stbi__tga_info(s, x, y, comp))
+ return 1;
+ #endif
+ return stbi__err("unknown image type", "Image not of any known type, or corrupt");
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ int result;
+ if (!f) return stbi__err("can't fopen", "Unable to open file");
+ result = stbi_info_from_file(f, x, y, comp);
+ fclose(f);
+ return result;
+}
+
+STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
+{
+ int r;
+ stbi__context s;
+ long pos = ftell(f);
+ stbi__start_file(&s, f);
+ r = stbi__info_main(&s,x,y,comp);
+ fseek(f,pos,SEEK_SET);
+ return r;
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__info_main(&s,x,y,comp);
+}
+
+STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
+ return stbi__info_main(&s,x,y,comp);
+}
+
+#endif // STB_IMAGE_IMPLEMENTATION
+
+/*
+ revision history:
+ 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now
+ 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+ 2.11 (2016-04-02) allocate large structures on the stack
+ remove white matting for transparent PSD
+ fix reported channel count for PNG & BMP
+ re-enable SSE2 in non-gcc 64-bit
+ support RGB-formatted JPEG
+ read 16-bit PNGs (only as 8-bit)
+ 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED
+ 2.09 (2016-01-16) allow comments in PNM files
+ 16-bit-per-pixel TGA (not bit-per-component)
+ info() for TGA could break due to .hdr handling
+ info() for BMP to shares code instead of sloppy parse
+ can use STBI_REALLOC_SIZED if allocator doesn't support realloc
+ code cleanup
+ 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
+ 2.07 (2015-09-13) fix compiler warnings
+ partial animated GIF support
+ limited 16-bpc PSD support
+ #ifdef unused functions
+ bug with < 92 byte PIC,PNM,HDR,TGA
+ 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value
+ 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
+ 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
+ 2.03 (2015-04-12) extra corruption checking (mmozeiko)
+ stbi_set_flip_vertically_on_load (nguillemot)
+ fix NEON support; fix mingw support
+ 2.02 (2015-01-19) fix incorrect assert, fix warning
+ 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
+ 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
+ 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
+ progressive JPEG (stb)
+ PGM/PPM support (Ken Miller)
+ STBI_MALLOC,STBI_REALLOC,STBI_FREE
+ GIF bugfix -- seemingly never worked
+ STBI_NO_*, STBI_ONLY_*
+ 1.48 (2014-12-14) fix incorrectly-named assert()
+ 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)
+ optimize PNG (ryg)
+ fix bug in interlaced PNG with user-specified channel count (stb)
+ 1.46 (2014-08-26)
+ fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG
+ 1.45 (2014-08-16)
+ fix MSVC-ARM internal compiler error by wrapping malloc
+ 1.44 (2014-08-07)
+ various warning fixes from Ronny Chevalier
+ 1.43 (2014-07-15)
+ fix MSVC-only compiler problem in code changed in 1.42
+ 1.42 (2014-07-09)
+ don't define _CRT_SECURE_NO_WARNINGS (affects user code)
+ fixes to stbi__cleanup_jpeg path
+ added STBI_ASSERT to avoid requiring assert.h
+ 1.41 (2014-06-25)
+ fix search&replace from 1.36 that messed up comments/error messages
+ 1.40 (2014-06-22)
+ fix gcc struct-initialization warning
+ 1.39 (2014-06-15)
+ fix to TGA optimization when req_comp != number of components in TGA;
+ fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)
+ add support for BMP version 5 (more ignored fields)
+ 1.38 (2014-06-06)
+ suppress MSVC warnings on integer casts truncating values
+ fix accidental rename of 'skip' field of I/O
+ 1.37 (2014-06-04)
+ remove duplicate typedef
+ 1.36 (2014-06-03)
+ convert to header file single-file library
+ if de-iphone isn't set, load iphone images color-swapped instead of returning NULL
+ 1.35 (2014-05-27)
+ various warnings
+ fix broken STBI_SIMD path
+ fix bug where stbi_load_from_file no longer left file pointer in correct place
+ fix broken non-easy path for 32-bit BMP (possibly never used)
+ TGA optimization by Arseny Kapoulkine
+ 1.34 (unknown)
+ use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case
+ 1.33 (2011-07-14)
+ make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
+ 1.32 (2011-07-13)
+ support for "info" function for all supported filetypes (SpartanJ)
+ 1.31 (2011-06-20)
+ a few more leak fixes, bug in PNG handling (SpartanJ)
+ 1.30 (2011-06-11)
+ added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
+ removed deprecated format-specific test/load functions
+ removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
+ error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
+ fix inefficiency in decoding 32-bit BMP (David Woo)
+ 1.29 (2010-08-16)
+ various warning fixes from Aurelien Pocheville
+ 1.28 (2010-08-01)
+ fix bug in GIF palette transparency (SpartanJ)
+ 1.27 (2010-08-01)
+ cast-to-stbi_uc to fix warnings
+ 1.26 (2010-07-24)
+ fix bug in file buffering for PNG reported by SpartanJ
+ 1.25 (2010-07-17)
+ refix trans_data warning (Won Chun)
+ 1.24 (2010-07-12)
+ perf improvements reading from files on platforms with lock-heavy fgetc()
+ minor perf improvements for jpeg
+ deprecated type-specific functions so we'll get feedback if they're needed
+ attempt to fix trans_data warning (Won Chun)
+ 1.23 fixed bug in iPhone support
+ 1.22 (2010-07-10)
+ removed image *writing* support
+ stbi_info support from Jetro Lauha
+ GIF support from Jean-Marc Lienher
+ iPhone PNG-extensions from James Brown
+ warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)
+ 1.21 fix use of 'stbi_uc' in header (reported by jon blow)
+ 1.20 added support for Softimage PIC, by Tom Seddon
+ 1.19 bug in interlaced PNG corruption check (found by ryg)
+ 1.18 (2008-08-02)
+ fix a threading bug (local mutable static)
+ 1.17 support interlaced PNG
+ 1.16 major bugfix - stbi__convert_format converted one too many pixels
+ 1.15 initialize some fields for thread safety
+ 1.14 fix threadsafe conversion bug
+ header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
+ 1.13 threadsafe
+ 1.12 const qualifiers in the API
+ 1.11 Support installable IDCT, colorspace conversion routines
+ 1.10 Fixes for 64-bit (don't use "unsigned long")
+ optimized upsampling by Fabian "ryg" Giesen
+ 1.09 Fix format-conversion for PSD code (bad global variables!)
+ 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz
+ 1.07 attempt to fix C++ warning/errors again
+ 1.06 attempt to fix C++ warning/errors again
+ 1.05 fix TGA loading to return correct *comp and use good luminance calc
+ 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free
+ 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR
+ 1.02 support for (subset of) HDR files, float interface for preferred access to them
+ 1.01 fix bug: possible bug in handling right-side up bmps... not sure
+ fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all
+ 1.00 interface to zlib that skips zlib header
+ 0.99 correct handling of alpha in palette
+ 0.98 TGA loader by lonesock; dynamically add loaders (untested)
+ 0.97 jpeg errors on too large a file; also catch another malloc failure
+ 0.96 fix detection of invalid v value - particleman@mollyrocket forum
+ 0.95 during header scan, seek to markers in case of padding
+ 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same
+ 0.93 handle jpegtran output; verbose errors
+ 0.92 read 4,8,16,24,32-bit BMP files of several formats
+ 0.91 output 24-bit Windows 3.0 BMP files
+ 0.90 fix a few more warnings; bump version number to approach 1.0
+ 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd
+ 0.60 fix compiling as c++
+ 0.59 fix warnings: merge Dave Moore's -Wall fixes
+ 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian
+ 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
+ 0.56 fix bug: zlib uncompressed mode len vs. nlen
+ 0.55 fix bug: restart_interval not initialized to 0
+ 0.54 allow NULL for 'int *comp'
+ 0.53 fix bug in png 3->4; speedup png decoding
+ 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments
+ 0.51 obey req_comp requests, 1-component jpegs return as 1-component,
+ on 'test' only check type, not whether we support this variant
+ 0.50 (2006-11-19)
+ first released version
+*/
diff --git a/src/external/stb_image_resize.h b/src/external/stb_image_resize.h
new file mode 100644
index 00000000..5214ad6e
--- /dev/null
+++ b/src/external/stb_image_resize.h
@@ -0,0 +1,2580 @@
+/* stb_image_resize - v0.92 - public domain image resizing
+ by Jorge L Rodriguez (@VinoBS) - 2014
+ http://github.com/nothings/stb
+
+ Written with emphasis on usability, portability, and efficiency. (No
+ SIMD or threads, so it be easily outperformed by libs that use those.)
+ Only scaling and translation is supported, no rotations or shears.
+ Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation.
+
+ COMPILING & LINKING
+ In one C/C++ file that #includes this file, do this:
+ #define STB_IMAGE_RESIZE_IMPLEMENTATION
+ before the #include. That will create the implementation in that file.
+
+ QUICKSTART
+ stbir_resize_uint8( input_pixels , in_w , in_h , 0,
+ output_pixels, out_w, out_h, 0, num_channels)
+ stbir_resize_float(...)
+ stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0,
+ output_pixels, out_w, out_h, 0,
+ num_channels , alpha_chan , 0)
+ stbir_resize_uint8_srgb_edgemode(
+ input_pixels , in_w , in_h , 0,
+ output_pixels, out_w, out_h, 0,
+ num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP)
+ // WRAP/REFLECT/ZERO
+
+ FULL API
+ See the "header file" section of the source for API documentation.
+
+ ADDITIONAL DOCUMENTATION
+
+ SRGB & FLOATING POINT REPRESENTATION
+ The sRGB functions presume IEEE floating point. If you do not have
+ IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use
+ a slower implementation.
+
+ MEMORY ALLOCATION
+ The resize functions here perform a single memory allocation using
+ malloc. To control the memory allocation, before the #include that
+ triggers the implementation, do:
+
+ #define STBIR_MALLOC(size,context) ...
+ #define STBIR_FREE(ptr,context) ...
+
+ Each resize function makes exactly one call to malloc/free, so to use
+ temp memory, store the temp memory in the context and return that.
+
+ ASSERT
+ Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
+
+ OPTIMIZATION
+ Define STBIR_SATURATE_INT to compute clamp values in-range using
+ integer operations instead of float operations. This may be faster
+ on some platforms.
+
+ DEFAULT FILTERS
+ For functions which don't provide explicit control over what filters
+ to use, you can change the compile-time defaults with
+
+ #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something
+ #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something
+
+ See stbir_filter in the header-file section for the list of filters.
+
+ NEW FILTERS
+ A number of 1D filter kernels are used. For a list of
+ supported filters see the stbir_filter enum. To add a new filter,
+ write a filter function and add it to stbir__filter_info_table.
+
+ PROGRESS
+ For interactive use with slow resize operations, you can install
+ a progress-report callback:
+
+ #define STBIR_PROGRESS_REPORT(val) some_func(val)
+
+ The parameter val is a float which goes from 0 to 1 as progress is made.
+
+ For example:
+
+ static void my_progress_report(float progress);
+ #define STBIR_PROGRESS_REPORT(val) my_progress_report(val)
+
+ #define STB_IMAGE_RESIZE_IMPLEMENTATION
+ #include "stb_image_resize.h"
+
+ static void my_progress_report(float progress)
+ {
+ printf("Progress: %f%%\n", progress*100);
+ }
+
+ MAX CHANNELS
+ If your image has more than 64 channels, define STBIR_MAX_CHANNELS
+ to the max you'll have.
+
+ ALPHA CHANNEL
+ Most of the resizing functions provide the ability to control how
+ the alpha channel of an image is processed. The important things
+ to know about this:
+
+ 1. The best mathematically-behaved version of alpha to use is
+ called "premultiplied alpha", in which the other color channels
+ have had the alpha value multiplied in. If you use premultiplied
+ alpha, linear filtering (such as image resampling done by this
+ library, or performed in texture units on GPUs) does the "right
+ thing". While premultiplied alpha is standard in the movie CGI
+ industry, it is still uncommon in the videogame/real-time world.
+
+ If you linearly filter non-premultiplied alpha, strange effects
+ occur. (For example, the average of 1% opaque bright green
+ and 99% opaque black produces 50% transparent dark green when
+ non-premultiplied, whereas premultiplied it produces 50%
+ transparent near-black. The former introduces green energy
+ that doesn't exist in the source image.)
+
+ 2. Artists should not edit premultiplied-alpha images; artists
+ want non-premultiplied alpha images. Thus, art tools generally output
+ non-premultiplied alpha images.
+
+ 3. You will get best results in most cases by converting images
+ to premultiplied alpha before processing them mathematically.
+
+ 4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the
+ resizer does not do anything special for the alpha channel;
+ it is resampled identically to other channels. This produces
+ the correct results for premultiplied-alpha images, but produces
+ less-than-ideal results for non-premultiplied-alpha images.
+
+ 5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED,
+ then the resizer weights the contribution of input pixels
+ based on their alpha values, or, equivalently, it multiplies
+ the alpha value into the color channels, resamples, then divides
+ by the resultant alpha value. Input pixels which have alpha=0 do
+ not contribute at all to output pixels unless _all_ of the input
+ pixels affecting that output pixel have alpha=0, in which case
+ the result for that pixel is the same as it would be without
+ STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for
+ input images in integer formats. For input images in float format,
+ input pixels with alpha=0 have no effect, and output pixels
+ which have alpha=0 will be 0 in all channels. (For float images,
+ you can manually achieve the same result by adding a tiny epsilon
+ value to the alpha channel of every image, and then subtracting
+ or clamping it at the end.)
+
+ 6. You can suppress the behavior described in #5 and make
+ all-0-alpha pixels have 0 in all channels by #defining
+ STBIR_NO_ALPHA_EPSILON.
+
+ 7. You can separately control whether the alpha channel is
+ interpreted as linear or affected by the colorspace. By default
+ it is linear; you almost never want to apply the colorspace.
+ (For example, graphics hardware does not apply sRGB conversion
+ to the alpha channel.)
+
+ ADDITIONAL CONTRIBUTORS
+ Sean Barrett: API design, optimizations
+ Aras Pranckevicius: bugfix
+
+ REVISIONS
+ 0.92 (2017-01-02) fix integer overflow on large (>2GB) images
+ 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
+ 0.90 (2014-09-17) first released version
+
+ LICENSE
+
+ This software is dual-licensed to the public domain and under the following
+ license: you are granted a perpetual, irrevocable license to copy, modify,
+ publish, and distribute this file as you see fit.
+
+ TODO
+ Don't decode all of the image data when only processing a partial tile
+ Don't use full-width decode buffers when only processing a partial tile
+ When processing wide images, break processing into tiles so data fits in L1 cache
+ Installable filters?
+ Resize that respects alpha test coverage
+ (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
+ https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
+*/
+
+#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
+#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
+
+#ifdef _MSC_VER
+typedef unsigned char stbir_uint8;
+typedef unsigned short stbir_uint16;
+typedef unsigned int stbir_uint32;
+#else
+#include <stdint.h>
+typedef uint8_t stbir_uint8;
+typedef uint16_t stbir_uint16;
+typedef uint32_t stbir_uint32;
+#endif
+
+#ifdef STB_IMAGE_RESIZE_STATIC
+#define STBIRDEF static
+#else
+#ifdef __cplusplus
+#define STBIRDEF extern "C"
+#else
+#define STBIRDEF extern
+#endif
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Easy-to-use API:
+//
+// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4)
+// * input_w is input image width (x-axis), input_h is input image height (y-axis)
+// * stride is the offset between successive rows of image data in memory, in bytes. you can
+// specify 0 to mean packed continuously in memory
+// * alpha channel is treated identically to other channels.
+// * colorspace is linear or sRGB as specified by function name
+// * returned result is 1 for success or 0 in case of an error.
+// #define STBIR_ASSERT() to trigger an assert on parameter validation errors.
+// * Memory required grows approximately linearly with input and output size, but with
+// discontinuities at input_w == output_w and input_h == output_h.
+// * These functions use a "default" resampling filter defined at compile time. To change the filter,
+// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE
+// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API.
+
+STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels);
+
+STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels);
+
+
+// The following functions interpret image data as gamma-corrected sRGB.
+// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
+// or otherwise provide the index of the alpha channel. Flags value
+// of 0 will probably do the right thing if you're not sure what
+// the flags mean.
+
+#define STBIR_ALPHA_CHANNEL_NONE -1
+
+// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
+// use alpha-weighted resampling (effectively premultiplying, resampling,
+// then unpremultiplying).
+#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0)
+// The specified alpha channel should be handled as gamma-corrected value even
+// when doing sRGB operations.
+#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1)
+
+STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags);
+
+
+typedef enum
+{
+ STBIR_EDGE_CLAMP = 1,
+ STBIR_EDGE_REFLECT = 2,
+ STBIR_EDGE_WRAP = 3,
+ STBIR_EDGE_ZERO = 4,
+} stbir_edge;
+
+// This function adds the ability to specify how requests to sample off the edge of the image are handled.
+STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode);
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Medium-complexity API
+//
+// This extends the easy-to-use API as follows:
+//
+// * Alpha-channel can be processed separately
+// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
+// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
+// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
+// * Filter can be selected explicitly
+// * uint16 image type
+// * sRGB colorspace available for all types
+// * context parameter for passing to STBIR_MALLOC
+
+typedef enum
+{
+ STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses
+ STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
+ STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering
+ STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
+ STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline
+ STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3
+} stbir_filter;
+
+typedef enum
+{
+ STBIR_COLORSPACE_LINEAR,
+ STBIR_COLORSPACE_SRGB,
+
+ STBIR_MAX_COLORSPACES,
+} stbir_colorspace;
+
+// The following functions are all identical except for the type of the image data
+
+STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
+ void *alloc_context);
+
+STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
+ void *alloc_context);
+
+STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
+ void *alloc_context);
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Full-complexity API
+//
+// This extends the medium API as follows:
+//
+// * uint32 image type
+// * not typesafe
+// * separate filter types for each axis
+// * separate edge modes for each axis
+// * can specify scale explicitly for subpixel correctness
+// * can specify image source tile using texture coordinates
+
+typedef enum
+{
+ STBIR_TYPE_UINT8 ,
+ STBIR_TYPE_UINT16,
+ STBIR_TYPE_UINT32,
+ STBIR_TYPE_FLOAT ,
+
+ STBIR_MAX_TYPES
+} stbir_datatype;
+
+STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ stbir_datatype datatype,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
+ stbir_filter filter_horizontal, stbir_filter filter_vertical,
+ stbir_colorspace space, void *alloc_context);
+
+STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ stbir_datatype datatype,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
+ stbir_filter filter_horizontal, stbir_filter filter_vertical,
+ stbir_colorspace space, void *alloc_context,
+ float x_scale, float y_scale,
+ float x_offset, float y_offset);
+
+STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ stbir_datatype datatype,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
+ stbir_filter filter_horizontal, stbir_filter filter_vertical,
+ stbir_colorspace space, void *alloc_context,
+ float s0, float t0, float s1, float t1);
+// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
+
+//
+//
+//// end header file /////////////////////////////////////////////////////
+#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
+
+
+
+
+
+#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION
+
+#ifndef STBIR_ASSERT
+#include <assert.h>
+#define STBIR_ASSERT(x) assert(x)
+#endif
+
+// For memset
+#include <string.h>
+
+#include <math.h>
+
+#ifndef STBIR_MALLOC
+#include <stdlib.h>
+#define STBIR_MALLOC(size,c) malloc(size)
+#define STBIR_FREE(ptr,c) free(ptr)
+#endif
+
+#ifndef _MSC_VER
+#ifdef __cplusplus
+#define stbir__inline inline
+#else
+#define stbir__inline
+#endif
+#else
+#define stbir__inline __forceinline
+#endif
+
+
+// should produce compiler error if size is wrong
+typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1];
+
+#ifdef _MSC_VER
+#define STBIR__NOTUSED(v) (void)(v)
+#else
+#define STBIR__NOTUSED(v) (void)sizeof(v)
+#endif
+
+#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))
+
+#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
+#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
+#endif
+
+#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
+#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
+#endif
+
+#ifndef STBIR_PROGRESS_REPORT
+#define STBIR_PROGRESS_REPORT(float_0_to_1)
+#endif
+
+#ifndef STBIR_MAX_CHANNELS
+#define STBIR_MAX_CHANNELS 64
+#endif
+
+#if STBIR_MAX_CHANNELS > 65536
+#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536."
+// because we store the indices in 16-bit variables
+#endif
+
+// This value is added to alpha just before premultiplication to avoid
+// zeroing out color values. It is equivalent to 2^-80. If you don't want
+// that behavior (it may interfere if you have floating point images with
+// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
+// disable it.
+#ifndef STBIR_ALPHA_EPSILON
+#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
+#endif
+
+
+
+#ifdef _MSC_VER
+#define STBIR__UNUSED_PARAM(v) (void)(v)
+#else
+#define STBIR__UNUSED_PARAM(v) (void)sizeof(v)
+#endif
+
+// must match stbir_datatype
+static unsigned char stbir__type_size[] = {
+ 1, // STBIR_TYPE_UINT8
+ 2, // STBIR_TYPE_UINT16
+ 4, // STBIR_TYPE_UINT32
+ 4, // STBIR_TYPE_FLOAT
+};
+
+// Kernel function centered at 0
+typedef float (stbir__kernel_fn)(float x, float scale);
+typedef float (stbir__support_fn)(float scale);
+
+typedef struct
+{
+ stbir__kernel_fn* kernel;
+ stbir__support_fn* support;
+} stbir__filter_info;
+
+// When upsampling, the contributors are which source pixels contribute.
+// When downsampling, the contributors are which destination pixels are contributed to.
+typedef struct
+{
+ int n0; // First contributing pixel
+ int n1; // Last contributing pixel
+} stbir__contributors;
+
+typedef struct
+{
+ const void* input_data;
+ int input_w;
+ int input_h;
+ int input_stride_bytes;
+
+ void* output_data;
+ int output_w;
+ int output_h;
+ int output_stride_bytes;
+
+ float s0, t0, s1, t1;
+
+ float horizontal_shift; // Units: output pixels
+ float vertical_shift; // Units: output pixels
+ float horizontal_scale;
+ float vertical_scale;
+
+ int channels;
+ int alpha_channel;
+ stbir_uint32 flags;
+ stbir_datatype type;
+ stbir_filter horizontal_filter;
+ stbir_filter vertical_filter;
+ stbir_edge edge_horizontal;
+ stbir_edge edge_vertical;
+ stbir_colorspace colorspace;
+
+ stbir__contributors* horizontal_contributors;
+ float* horizontal_coefficients;
+
+ stbir__contributors* vertical_contributors;
+ float* vertical_coefficients;
+
+ int decode_buffer_pixels;
+ float* decode_buffer;
+
+ float* horizontal_buffer;
+
+ // cache these because ceil/floor are inexplicably showing up in profile
+ int horizontal_coefficient_width;
+ int vertical_coefficient_width;
+ int horizontal_filter_pixel_width;
+ int vertical_filter_pixel_width;
+ int horizontal_filter_pixel_margin;
+ int vertical_filter_pixel_margin;
+ int horizontal_num_contributors;
+ int vertical_num_contributors;
+
+ int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
+ int ring_buffer_first_scanline;
+ int ring_buffer_last_scanline;
+ int ring_buffer_begin_index;
+ float* ring_buffer;
+
+ float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
+
+ int horizontal_contributors_size;
+ int horizontal_coefficients_size;
+ int vertical_contributors_size;
+ int vertical_coefficients_size;
+ int decode_buffer_size;
+ int horizontal_buffer_size;
+ int ring_buffer_size;
+ int encode_buffer_size;
+} stbir__info;
+
+static stbir__inline int stbir__min(int a, int b)
+{
+ return a < b ? a : b;
+}
+
+static stbir__inline int stbir__max(int a, int b)
+{
+ return a > b ? a : b;
+}
+
+static stbir__inline float stbir__saturate(float x)
+{
+ if (x < 0)
+ return 0;
+
+ if (x > 1)
+ return 1;
+
+ return x;
+}
+
+#ifdef STBIR_SATURATE_INT
+static stbir__inline stbir_uint8 stbir__saturate8(int x)
+{
+ if ((unsigned int) x <= 255)
+ return x;
+
+ if (x < 0)
+ return 0;
+
+ return 255;
+}
+
+static stbir__inline stbir_uint16 stbir__saturate16(int x)
+{
+ if ((unsigned int) x <= 65535)
+ return x;
+
+ if (x < 0)
+ return 0;
+
+ return 65535;
+}
+#endif
+
+static float stbir__srgb_uchar_to_linear_float[256] = {
+ 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
+ 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,
+ 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,
+ 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,
+ 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,
+ 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,
+ 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,
+ 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
+ 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,
+ 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,
+ 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,
+ 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,
+ 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,
+ 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,
+ 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
+ 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,
+ 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,
+ 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,
+ 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,
+ 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,
+ 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,
+ 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
+ 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,
+ 0.982251f, 0.991102f, 1.0f
+};
+
+static float stbir__srgb_to_linear(float f)
+{
+ if (f <= 0.04045f)
+ return f / 12.92f;
+ else
+ return (float)pow((f + 0.055f) / 1.055f, 2.4f);
+}
+
+static float stbir__linear_to_srgb(float f)
+{
+ if (f <= 0.0031308f)
+ return f * 12.92f;
+ else
+ return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f;
+}
+
+#ifndef STBIR_NON_IEEE_FLOAT
+// From https://gist.github.com/rygorous/2203834
+
+typedef union
+{
+ stbir_uint32 u;
+ float f;
+} stbir__FP32;
+
+static const stbir_uint32 fp32_to_srgb8_tab4[104] = {
+ 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
+ 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
+ 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
+ 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
+ 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
+ 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
+ 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
+ 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
+ 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
+ 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
+ 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
+ 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
+ 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
+};
+
+static stbir_uint8 stbir__linear_to_srgb_uchar(float in)
+{
+ static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
+ static const stbir__FP32 minval = { (127-13) << 23 };
+ stbir_uint32 tab,bias,scale,t;
+ stbir__FP32 f;
+
+ // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
+ // The tests are carefully written so that NaNs map to 0, same as in the reference
+ // implementation.
+ if (!(in > minval.f)) // written this way to catch NaNs
+ in = minval.f;
+ if (in > almostone.f)
+ in = almostone.f;
+
+ // Do the table lookup and unpack bias, scale
+ f.f = in;
+ tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
+ bias = (tab >> 16) << 9;
+ scale = tab & 0xffff;
+
+ // Grab next-highest mantissa bits and perform linear interpolation
+ t = (f.u >> 12) & 0xff;
+ return (unsigned char) ((bias + scale*t) >> 16);
+}
+
+#else
+// sRGB transition values, scaled by 1<<28
+static int stbir__srgb_offset_to_linear_scaled[256] =
+{
+ 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603,
+ 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926,
+ 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148,
+ 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856,
+ 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731,
+ 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369,
+ 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021,
+ 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073,
+ 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389,
+ 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552,
+ 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066,
+ 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490,
+ 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568,
+ 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316,
+ 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096,
+ 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700,
+ 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376,
+ 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912,
+ 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648,
+ 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512,
+ 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072,
+ 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544,
+ 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832,
+ 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528,
+ 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968,
+ 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184,
+ 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992,
+ 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968,
+ 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480,
+ 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656,
+ 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464,
+ 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664,
+};
+
+static stbir_uint8 stbir__linear_to_srgb_uchar(float f)
+{
+ int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp
+ int v = 0;
+ int i;
+
+ // Refine the guess with a short binary search.
+ i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+
+ return (stbir_uint8) v;
+}
+#endif
+
+static float stbir__filter_trapezoid(float x, float scale)
+{
+ float halfscale = scale / 2;
+ float t = 0.5f + halfscale;
+ STBIR_ASSERT(scale <= 1);
+
+ x = (float)fabs(x);
+
+ if (x >= t)
+ return 0;
+ else
+ {
+ float r = 0.5f - halfscale;
+ if (x <= r)
+ return 1;
+ else
+ return (t - x) / scale;
+ }
+}
+
+static float stbir__support_trapezoid(float scale)
+{
+ STBIR_ASSERT(scale <= 1);
+ return 0.5f + scale / 2;
+}
+
+static float stbir__filter_triangle(float x, float s)
+{
+ STBIR__UNUSED_PARAM(s);
+
+ x = (float)fabs(x);
+
+ if (x <= 1.0f)
+ return 1 - x;
+ else
+ return 0;
+}
+
+static float stbir__filter_cubic(float x, float s)
+{
+ STBIR__UNUSED_PARAM(s);
+
+ x = (float)fabs(x);
+
+ if (x < 1.0f)
+ return (4 + x*x*(3*x - 6))/6;
+ else if (x < 2.0f)
+ return (8 + x*(-12 + x*(6 - x)))/6;
+
+ return (0.0f);
+}
+
+static float stbir__filter_catmullrom(float x, float s)
+{
+ STBIR__UNUSED_PARAM(s);
+
+ x = (float)fabs(x);
+
+ if (x < 1.0f)
+ return 1 - x*x*(2.5f - 1.5f*x);
+ else if (x < 2.0f)
+ return 2 - x*(4 + x*(0.5f*x - 2.5f));
+
+ return (0.0f);
+}
+
+static float stbir__filter_mitchell(float x, float s)
+{
+ STBIR__UNUSED_PARAM(s);
+
+ x = (float)fabs(x);
+
+ if (x < 1.0f)
+ return (16 + x*x*(21 * x - 36))/18;
+ else if (x < 2.0f)
+ return (32 + x*(-60 + x*(36 - 7*x)))/18;
+
+ return (0.0f);
+}
+
+static float stbir__support_zero(float s)
+{
+ STBIR__UNUSED_PARAM(s);
+ return 0;
+}
+
+static float stbir__support_one(float s)
+{
+ STBIR__UNUSED_PARAM(s);
+ return 1;
+}
+
+static float stbir__support_two(float s)
+{
+ STBIR__UNUSED_PARAM(s);
+ return 2;
+}
+
+static stbir__filter_info stbir__filter_info_table[] = {
+ { NULL, stbir__support_zero },
+ { stbir__filter_trapezoid, stbir__support_trapezoid },
+ { stbir__filter_triangle, stbir__support_one },
+ { stbir__filter_cubic, stbir__support_two },
+ { stbir__filter_catmullrom, stbir__support_two },
+ { stbir__filter_mitchell, stbir__support_two },
+};
+
+stbir__inline static int stbir__use_upsampling(float ratio)
+{
+ return ratio > 1;
+}
+
+stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info)
+{
+ return stbir__use_upsampling(stbir_info->horizontal_scale);
+}
+
+stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info)
+{
+ return stbir__use_upsampling(stbir_info->vertical_scale);
+}
+
+// This is the maximum number of input samples that can affect an output sample
+// with the given filter
+static int stbir__get_filter_pixel_width(stbir_filter filter, float scale)
+{
+ STBIR_ASSERT(filter != 0);
+ STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
+
+ if (stbir__use_upsampling(scale))
+ return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2);
+ else
+ return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale);
+}
+
+// This is how much to expand buffers to account for filters seeking outside
+// the image boundaries.
+static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale)
+{
+ return stbir__get_filter_pixel_width(filter, scale) / 2;
+}
+
+static int stbir__get_coefficient_width(stbir_filter filter, float scale)
+{
+ if (stbir__use_upsampling(scale))
+ return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2);
+ else
+ return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2);
+}
+
+static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size)
+{
+ if (stbir__use_upsampling(scale))
+ return output_size;
+ else
+ return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2);
+}
+
+static int stbir__get_total_horizontal_coefficients(stbir__info* info)
+{
+ return info->horizontal_num_contributors
+ * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
+}
+
+static int stbir__get_total_vertical_coefficients(stbir__info* info)
+{
+ return info->vertical_num_contributors
+ * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale);
+}
+
+static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n)
+{
+ return &contributors[n];
+}
+
+// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample,
+// if you change it here change it there too.
+static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c)
+{
+ int width = stbir__get_coefficient_width(filter, scale);
+ return &coefficients[width*n + c];
+}
+
+static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
+{
+ switch (edge)
+ {
+ case STBIR_EDGE_ZERO:
+ return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later
+
+ case STBIR_EDGE_CLAMP:
+ if (n < 0)
+ return 0;
+
+ if (n >= max)
+ return max - 1;
+
+ return n; // NOTREACHED
+
+ case STBIR_EDGE_REFLECT:
+ {
+ if (n < 0)
+ {
+ if (n < max)
+ return -n;
+ else
+ return max - 1;
+ }
+
+ if (n >= max)
+ {
+ int max2 = max * 2;
+ if (n >= max2)
+ return 0;
+ else
+ return max2 - n - 1;
+ }
+
+ return n; // NOTREACHED
+ }
+
+ case STBIR_EDGE_WRAP:
+ if (n >= 0)
+ return (n % max);
+ else
+ {
+ int m = (-n) % max;
+
+ if (m != 0)
+ m = max - m;
+
+ return (m);
+ }
+ return n; // NOTREACHED
+
+ default:
+ STBIR_ASSERT(!"Unimplemented edge type");
+ return 0;
+ }
+}
+
+stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max)
+{
+ // avoid per-pixel switch
+ if (n >= 0 && n < max)
+ return n;
+ return stbir__edge_wrap_slow(edge, n, max);
+}
+
+// What input pixels contribute to this output pixel?
+static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out)
+{
+ float out_pixel_center = (float)n + 0.5f;
+ float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius;
+ float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius;
+
+ float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio;
+ float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio;
+
+ *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio;
+ *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5));
+ *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5));
+}
+
+// What output pixels does this input pixel contribute to?
+static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in)
+{
+ float in_pixel_center = (float)n + 0.5f;
+ float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;
+ float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;
+
+ float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift;
+ float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift;
+
+ *out_center_of_in = in_pixel_center * scale_ratio - out_shift;
+ *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5));
+ *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5));
+}
+
+static void stbir__calculate_coefficients_upsample(stbir__info* stbir_info, stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group)
+{
+ int i;
+ float total_filter = 0;
+ float filter_scale;
+
+ STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
+
+ contributor->n0 = in_first_pixel;
+ contributor->n1 = in_last_pixel;
+
+ STBIR_ASSERT(contributor->n1 >= contributor->n0);
+
+ for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
+ {
+ float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;
+ coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale);
+
+ // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.)
+ if (i == 0 && !coefficient_group[i])
+ {
+ contributor->n0 = ++in_first_pixel;
+ i--;
+ continue;
+ }
+
+ total_filter += coefficient_group[i];
+ }
+
+ STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
+
+ STBIR_ASSERT(total_filter > 0.9);
+ STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
+
+ // Make sure the sum of all coefficients is 1.
+ filter_scale = 1 / total_filter;
+
+ for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
+ coefficient_group[i] *= filter_scale;
+
+ for (i = in_last_pixel - in_first_pixel; i >= 0; i--)
+ {
+ if (coefficient_group[i])
+ break;
+
+ // This line has no weight. We can skip it.
+ contributor->n1 = contributor->n0 + i - 1;
+ }
+}
+
+static void stbir__calculate_coefficients_downsample(stbir__info* stbir_info, stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group)
+{
+ int i;
+
+ STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
+
+ contributor->n0 = out_first_pixel;
+ contributor->n1 = out_last_pixel;
+
+ STBIR_ASSERT(contributor->n1 >= contributor->n0);
+
+ for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
+ {
+ float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;
+ float x = out_pixel_center - out_center_of_in;
+ coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
+ }
+
+ STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
+
+ for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
+ {
+ if (coefficient_group[i])
+ break;
+
+ // This line has no weight. We can skip it.
+ contributor->n1 = contributor->n0 + i - 1;
+ }
+}
+
+static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info, stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
+{
+ int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
+ int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
+ int i, j;
+ int skip;
+
+ for (i = 0; i < output_size; i++)
+ {
+ float scale;
+ float total = 0;
+
+ for (j = 0; j < num_contributors; j++)
+ {
+ if (i >= contributors[j].n0 && i <= contributors[j].n1)
+ {
+ float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0);
+ total += coefficient;
+ }
+ else if (i < contributors[j].n0)
+ break;
+ }
+
+ STBIR_ASSERT(total > 0.9f);
+ STBIR_ASSERT(total < 1.1f);
+
+ scale = 1 / total;
+
+ for (j = 0; j < num_contributors; j++)
+ {
+ if (i >= contributors[j].n0 && i <= contributors[j].n1)
+ *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale;
+ else if (i < contributors[j].n0)
+ break;
+ }
+ }
+
+ // Optimize: Skip zero coefficients and contributions outside of image bounds.
+ // Do this after normalizing because normalization depends on the n0/n1 values.
+ for (j = 0; j < num_contributors; j++)
+ {
+ int range, max, width;
+
+ skip = 0;
+ while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0)
+ skip++;
+
+ contributors[j].n0 += skip;
+
+ while (contributors[j].n0 < 0)
+ {
+ contributors[j].n0++;
+ skip++;
+ }
+
+ range = contributors[j].n1 - contributors[j].n0 + 1;
+ max = stbir__min(num_coefficients, range);
+
+ width = stbir__get_coefficient_width(filter, scale_ratio);
+ for (i = 0; i < max; i++)
+ {
+ if (i + skip >= width)
+ break;
+
+ *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip);
+ }
+
+ continue;
+ }
+
+ // Using min to avoid writing into invalid pixels.
+ for (i = 0; i < num_contributors; i++)
+ contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1);
+}
+
+// Each scan line uses the same kernel values so we should calculate the kernel
+// values once and then we can use them for every scan line.
+static void stbir__calculate_filters(stbir__info* stbir_info, stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
+{
+ int n;
+ int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
+
+ if (stbir__use_upsampling(scale_ratio))
+ {
+ float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio;
+
+ // Looping through out pixels
+ for (n = 0; n < total_contributors; n++)
+ {
+ float in_center_of_out; // Center of the current out pixel in the in pixel space
+ int in_first_pixel, in_last_pixel;
+
+ stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
+
+ stbir__calculate_coefficients_upsample(stbir_info, filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
+ }
+ }
+ else
+ {
+ float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio;
+
+ // Looping through in pixels
+ for (n = 0; n < total_contributors; n++)
+ {
+ float out_center_of_in; // Center of the current out pixel in the in pixel space
+ int out_first_pixel, out_last_pixel;
+ int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio);
+
+ stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
+
+ stbir__calculate_coefficients_downsample(stbir_info, filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
+ }
+
+ stbir__normalize_downsample_coefficients(stbir_info, contributors, coefficients, filter, scale_ratio, shift, input_size, output_size);
+ }
+}
+
+static float* stbir__get_decode_buffer(stbir__info* stbir_info)
+{
+ // The 0 index of the decode buffer starts after the margin. This makes
+ // it okay to use negative indexes on the decode buffer.
+ return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels];
+}
+
+#define STBIR__DECODE(type, colorspace) ((type) * (STBIR_MAX_COLORSPACES) + (colorspace))
+
+static void stbir__decode_scanline(stbir__info* stbir_info, int n)
+{
+ int c;
+ int channels = stbir_info->channels;
+ int alpha_channel = stbir_info->alpha_channel;
+ int type = stbir_info->type;
+ int colorspace = stbir_info->colorspace;
+ int input_w = stbir_info->input_w;
+ size_t input_stride_bytes = stbir_info->input_stride_bytes;
+ float* decode_buffer = stbir__get_decode_buffer(stbir_info);
+ stbir_edge edge_horizontal = stbir_info->edge_horizontal;
+ stbir_edge edge_vertical = stbir_info->edge_vertical;
+ size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
+ const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset;
+ int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
+ int decode = STBIR__DECODE(type, colorspace);
+
+ int x = -stbir_info->horizontal_filter_pixel_margin;
+
+ // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input,
+ // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO
+ if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h))
+ {
+ for (; x < max_x; x++)
+ for (c = 0; c < channels; c++)
+ decode_buffer[x*channels + c] = 0;
+ return;
+ }
+
+ switch (decode)
+ {
+ case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / 255;
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]];
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / 255;
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / 65535;
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / 65535);
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / 65535;
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / 4294967295);
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / 4294967295));
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / 4294967295);
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c];
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]);
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel];
+ }
+
+ break;
+
+ default:
+ STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
+ break;
+ }
+
+ if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED))
+ {
+ for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+
+ // If the alpha value is 0 it will clobber the color values. Make sure it's not.
+ float alpha = decode_buffer[decode_pixel_index + alpha_channel];
+#ifndef STBIR_NO_ALPHA_EPSILON
+ if (stbir_info->type != STBIR_TYPE_FLOAT) {
+ alpha += STBIR_ALPHA_EPSILON;
+ decode_buffer[decode_pixel_index + alpha_channel] = alpha;
+ }
+#endif
+ for (c = 0; c < channels; c++)
+ {
+ if (c == alpha_channel)
+ continue;
+
+ decode_buffer[decode_pixel_index + c] *= alpha;
+ }
+ }
+ }
+
+ if (edge_horizontal == STBIR_EDGE_ZERO)
+ {
+ for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++)
+ {
+ for (c = 0; c < channels; c++)
+ decode_buffer[x*channels + c] = 0;
+ }
+ for (x = input_w; x < max_x; x++)
+ {
+ for (c = 0; c < channels; c++)
+ decode_buffer[x*channels + c] = 0;
+ }
+ }
+}
+
+static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length)
+{
+ return &ring_buffer[index * ring_buffer_length];
+}
+
+static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
+{
+ int ring_buffer_index;
+ float* ring_buffer;
+
+ if (stbir_info->ring_buffer_begin_index < 0)
+ {
+ ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
+ stbir_info->ring_buffer_first_scanline = n;
+ }
+ else
+ {
+ ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline) + 1) % stbir_info->vertical_filter_pixel_width;
+ STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
+ }
+
+ ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float));
+ memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
+
+ stbir_info->ring_buffer_last_scanline = n;
+
+ return ring_buffer;
+}
+
+
+static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n, float* output_buffer)
+{
+ int x, k;
+ int output_w = stbir_info->output_w;
+ int kernel_pixel_width = stbir_info->horizontal_filter_pixel_width;
+ int channels = stbir_info->channels;
+ float* decode_buffer = stbir__get_decode_buffer(stbir_info);
+ stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
+ float* horizontal_coefficients = stbir_info->horizontal_coefficients;
+ int coefficient_width = stbir_info->horizontal_coefficient_width;
+
+ for (x = 0; x < output_w; x++)
+ {
+ int n0 = horizontal_contributors[x].n0;
+ int n1 = horizontal_contributors[x].n1;
+
+ int out_pixel_index = x * channels;
+ int coefficient_group = coefficient_width * x;
+ int coefficient_counter = 0;
+
+ STBIR_ASSERT(n1 >= n0);
+ STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
+ STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
+ STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
+ STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
+
+ switch (channels) {
+ case 1:
+ for (k = n0; k <= n1; k++)
+ {
+ int in_pixel_index = k * 1;
+ float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
+ STBIR_ASSERT(coefficient != 0);
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ }
+ break;
+ case 2:
+ for (k = n0; k <= n1; k++)
+ {
+ int in_pixel_index = k * 2;
+ float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
+ STBIR_ASSERT(coefficient != 0);
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
+ }
+ break;
+ case 3:
+ for (k = n0; k <= n1; k++)
+ {
+ int in_pixel_index = k * 3;
+ float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
+ STBIR_ASSERT(coefficient != 0);
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
+ output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
+ }
+ break;
+ case 4:
+ for (k = n0; k <= n1; k++)
+ {
+ int in_pixel_index = k * 4;
+ float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
+ STBIR_ASSERT(coefficient != 0);
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
+ output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
+ output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
+ }
+ break;
+ default:
+ for (k = n0; k <= n1; k++)
+ {
+ int in_pixel_index = k * channels;
+ float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
+ int c;
+ STBIR_ASSERT(coefficient != 0);
+ for (c = 0; c < channels; c++)
+ output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
+ }
+ break;
+ }
+ }
+}
+
+static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n, float* output_buffer)
+{
+ int x, k;
+ int input_w = stbir_info->input_w;
+ int output_w = stbir_info->output_w;
+ int kernel_pixel_width = stbir_info->horizontal_filter_pixel_width;
+ int channels = stbir_info->channels;
+ float* decode_buffer = stbir__get_decode_buffer(stbir_info);
+ stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
+ float* horizontal_coefficients = stbir_info->horizontal_coefficients;
+ int coefficient_width = stbir_info->horizontal_coefficient_width;
+ int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
+ int max_x = input_w + filter_pixel_margin * 2;
+
+ STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info));
+
+ switch (channels) {
+ case 1:
+ for (x = 0; x < max_x; x++)
+ {
+ int n0 = horizontal_contributors[x].n0;
+ int n1 = horizontal_contributors[x].n1;
+
+ int in_x = x - filter_pixel_margin;
+ int in_pixel_index = in_x * 1;
+ int max_n = n1;
+ int coefficient_group = coefficient_width * x;
+
+ for (k = n0; k <= max_n; k++)
+ {
+ int out_pixel_index = k * 1;
+ float coefficient = horizontal_coefficients[coefficient_group + k - n0];
+ STBIR_ASSERT(coefficient != 0);
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ }
+ }
+ break;
+
+ case 2:
+ for (x = 0; x < max_x; x++)
+ {
+ int n0 = horizontal_contributors[x].n0;
+ int n1 = horizontal_contributors[x].n1;
+
+ int in_x = x - filter_pixel_margin;
+ int in_pixel_index = in_x * 2;
+ int max_n = n1;
+ int coefficient_group = coefficient_width * x;
+
+ for (k = n0; k <= max_n; k++)
+ {
+ int out_pixel_index = k * 2;
+ float coefficient = horizontal_coefficients[coefficient_group + k - n0];
+ STBIR_ASSERT(coefficient != 0);
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
+ }
+ }
+ break;
+
+ case 3:
+ for (x = 0; x < max_x; x++)
+ {
+ int n0 = horizontal_contributors[x].n0;
+ int n1 = horizontal_contributors[x].n1;
+
+ int in_x = x - filter_pixel_margin;
+ int in_pixel_index = in_x * 3;
+ int max_n = n1;
+ int coefficient_group = coefficient_width * x;
+
+ for (k = n0; k <= max_n; k++)
+ {
+ int out_pixel_index = k * 3;
+ float coefficient = horizontal_coefficients[coefficient_group + k - n0];
+ STBIR_ASSERT(coefficient != 0);
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
+ output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
+ }
+ }
+ break;
+
+ case 4:
+ for (x = 0; x < max_x; x++)
+ {
+ int n0 = horizontal_contributors[x].n0;
+ int n1 = horizontal_contributors[x].n1;
+
+ int in_x = x - filter_pixel_margin;
+ int in_pixel_index = in_x * 4;
+ int max_n = n1;
+ int coefficient_group = coefficient_width * x;
+
+ for (k = n0; k <= max_n; k++)
+ {
+ int out_pixel_index = k * 4;
+ float coefficient = horizontal_coefficients[coefficient_group + k - n0];
+ STBIR_ASSERT(coefficient != 0);
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
+ output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
+ output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
+ }
+ }
+ break;
+
+ default:
+ for (x = 0; x < max_x; x++)
+ {
+ int n0 = horizontal_contributors[x].n0;
+ int n1 = horizontal_contributors[x].n1;
+
+ int in_x = x - filter_pixel_margin;
+ int in_pixel_index = in_x * channels;
+ int max_n = n1;
+ int coefficient_group = coefficient_width * x;
+
+ for (k = n0; k <= max_n; k++)
+ {
+ int c;
+ int out_pixel_index = k * channels;
+ float coefficient = horizontal_coefficients[coefficient_group + k - n0];
+ STBIR_ASSERT(coefficient != 0);
+ for (c = 0; c < channels; c++)
+ output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
+ }
+ }
+ break;
+ }
+}
+
+static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n)
+{
+ // Decode the nth scanline from the source image into the decode buffer.
+ stbir__decode_scanline(stbir_info, n);
+
+ // Now resample it into the ring buffer.
+ if (stbir__use_width_upsampling(stbir_info))
+ stbir__resample_horizontal_upsample(stbir_info, n, stbir__add_empty_ring_buffer_entry(stbir_info, n));
+ else
+ stbir__resample_horizontal_downsample(stbir_info, n, stbir__add_empty_ring_buffer_entry(stbir_info, n));
+
+ // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
+}
+
+static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n)
+{
+ // Decode the nth scanline from the source image into the decode buffer.
+ stbir__decode_scanline(stbir_info, n);
+
+ memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float));
+
+ // Now resample it into the horizontal buffer.
+ if (stbir__use_width_upsampling(stbir_info))
+ stbir__resample_horizontal_upsample(stbir_info, n, stbir_info->horizontal_buffer);
+ else
+ stbir__resample_horizontal_downsample(stbir_info, n, stbir_info->horizontal_buffer);
+
+ // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
+}
+
+// Get the specified scan line from the ring buffer.
+static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_size, int ring_buffer_length)
+{
+ int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_size;
+ return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
+}
+
+
+static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode)
+{
+ int x;
+ int n;
+ int num_nonalpha;
+ stbir_uint16 nonalpha[STBIR_MAX_CHANNELS];
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
+ {
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ float alpha = encode_buffer[pixel_index + alpha_channel];
+ float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
+
+ // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb
+ for (n = 0; n < channels; n++)
+ if (n != alpha_channel)
+ encode_buffer[pixel_index + n] *= reciprocal_alpha;
+
+ // We added in a small epsilon to prevent the color channel from being deleted with zero alpha.
+ // Because we only add it for integer types, it will automatically be discarded on integer
+ // conversion, so we don't need to subtract it back out (which would be problematic for
+ // numeric precision reasons).
+ }
+ }
+
+ // build a table of all channels that need colorspace correction, so
+ // we don't perform colorspace correction on channels that don't need it.
+ for (x=0, num_nonalpha=0; x < channels; ++x)
+ if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ nonalpha[num_nonalpha++] = x;
+
+ #define STBIR__ROUND_INT(f) ((int) ((f)+0.5))
+ #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
+
+ #ifdef STBIR__SATURATE_INT
+ #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * 255 ))
+ #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * 65535))
+ #else
+ #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * 255 )
+ #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * 65535)
+ #endif
+
+ switch (decode)
+ {
+ case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < channels; n++)
+ {
+ int index = pixel_index + n;
+ ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]);
+ }
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < num_nonalpha; n++)
+ {
+ int index = pixel_index + nonalpha[n];
+ ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]);
+ }
+
+ if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]);
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < channels; n++)
+ {
+ int index = pixel_index + n;
+ ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]);
+ }
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < num_nonalpha; n++)
+ {
+ int index = pixel_index + nonalpha[n];
+ ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * 65535);
+ }
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]);
+ }
+
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < channels; n++)
+ {
+ int index = pixel_index + n;
+ ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * 4294967295);
+ }
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < num_nonalpha; n++)
+ {
+ int index = pixel_index + nonalpha[n];
+ ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * 4294967295);
+ }
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * 4294967295);
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < channels; n++)
+ {
+ int index = pixel_index + n;
+ ((float*)output_buffer)[index] = encode_buffer[index];
+ }
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < num_nonalpha; n++)
+ {
+ int index = pixel_index + nonalpha[n];
+ ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]);
+ }
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel];
+ }
+ break;
+
+ default:
+ STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
+ break;
+ }
+}
+
+static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, int in_first_scanline, int in_last_scanline, float in_center_of_out)
+{
+ int x, k;
+ int output_w = stbir_info->output_w;
+ stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
+ float* vertical_coefficients = stbir_info->vertical_coefficients;
+ int channels = stbir_info->channels;
+ int alpha_channel = stbir_info->alpha_channel;
+ int type = stbir_info->type;
+ int colorspace = stbir_info->colorspace;
+ int kernel_pixel_width = stbir_info->vertical_filter_pixel_width;
+ void* output_data = stbir_info->output_data;
+ float* encode_buffer = stbir_info->encode_buffer;
+ int decode = STBIR__DECODE(type, colorspace);
+ int coefficient_width = stbir_info->vertical_coefficient_width;
+ int coefficient_counter;
+ int contributor = n;
+
+ float* ring_buffer = stbir_info->ring_buffer;
+ int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
+ int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
+ int ring_buffer_last_scanline = stbir_info->ring_buffer_last_scanline;
+ int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
+
+ int n0,n1, output_row_start;
+ int coefficient_group = coefficient_width * contributor;
+
+ n0 = vertical_contributors[contributor].n0;
+ n1 = vertical_contributors[contributor].n1;
+
+ output_row_start = n * stbir_info->output_stride_bytes;
+
+ STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
+
+ memset(encode_buffer, 0, output_w * sizeof(float) * channels);
+
+ // I tried reblocking this for better cache usage of encode_buffer
+ // (using x_outer, k, x_inner), but it lost speed. -- stb
+
+ coefficient_counter = 0;
+ switch (channels) {
+ case 1:
+ for (k = n0; k <= n1; k++)
+ {
+ int coefficient_index = coefficient_counter++;
+ float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
+ float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
+ for (x = 0; x < output_w; ++x)
+ {
+ int in_pixel_index = x * 1;
+ encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
+ }
+ }
+ break;
+ case 2:
+ for (k = n0; k <= n1; k++)
+ {
+ int coefficient_index = coefficient_counter++;
+ float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
+ float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
+ for (x = 0; x < output_w; ++x)
+ {
+ int in_pixel_index = x * 2;
+ encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
+ encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
+ }
+ }
+ break;
+ case 3:
+ for (k = n0; k <= n1; k++)
+ {
+ int coefficient_index = coefficient_counter++;
+ float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
+ float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
+ for (x = 0; x < output_w; ++x)
+ {
+ int in_pixel_index = x * 3;
+ encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
+ encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
+ encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
+ }
+ }
+ break;
+ case 4:
+ for (k = n0; k <= n1; k++)
+ {
+ int coefficient_index = coefficient_counter++;
+ float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
+ float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
+ for (x = 0; x < output_w; ++x)
+ {
+ int in_pixel_index = x * 4;
+ encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
+ encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
+ encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
+ encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient;
+ }
+ }
+ break;
+ default:
+ for (k = n0; k <= n1; k++)
+ {
+ int coefficient_index = coefficient_counter++;
+ float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
+ float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
+ for (x = 0; x < output_w; ++x)
+ {
+ int in_pixel_index = x * channels;
+ int c;
+ for (c = 0; c < channels; c++)
+ encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient;
+ }
+ }
+ break;
+ }
+ stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
+}
+
+static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n, int in_first_scanline, int in_last_scanline, float in_center_of_out)
+{
+ int x, k;
+ int output_w = stbir_info->output_w;
+ int output_h = stbir_info->output_h;
+ stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
+ float* vertical_coefficients = stbir_info->vertical_coefficients;
+ int channels = stbir_info->channels;
+ int kernel_pixel_width = stbir_info->vertical_filter_pixel_width;
+ void* output_data = stbir_info->output_data;
+ float* horizontal_buffer = stbir_info->horizontal_buffer;
+ int coefficient_width = stbir_info->vertical_coefficient_width;
+ int contributor = n + stbir_info->vertical_filter_pixel_margin;
+
+ float* ring_buffer = stbir_info->ring_buffer;
+ int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
+ int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
+ int ring_buffer_last_scanline = stbir_info->ring_buffer_last_scanline;
+ int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
+ int n0,n1;
+
+ n0 = vertical_contributors[contributor].n0;
+ n1 = vertical_contributors[contributor].n1;
+
+ STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
+
+ for (k = n0; k <= n1; k++)
+ {
+ int coefficient_index = k - n0;
+ int coefficient_group = coefficient_width * contributor;
+ float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
+
+ float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
+
+ switch (channels) {
+ case 1:
+ for (x = 0; x < output_w; x++)
+ {
+ int in_pixel_index = x * 1;
+ ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
+ }
+ break;
+ case 2:
+ for (x = 0; x < output_w; x++)
+ {
+ int in_pixel_index = x * 2;
+ ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
+ ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
+ }
+ break;
+ case 3:
+ for (x = 0; x < output_w; x++)
+ {
+ int in_pixel_index = x * 3;
+ ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
+ ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
+ ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
+ }
+ break;
+ case 4:
+ for (x = 0; x < output_w; x++)
+ {
+ int in_pixel_index = x * 4;
+ ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
+ ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
+ ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
+ ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient;
+ }
+ break;
+ default:
+ for (x = 0; x < output_w; x++)
+ {
+ int in_pixel_index = x * channels;
+
+ int c;
+ for (c = 0; c < channels; c++)
+ ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient;
+ }
+ break;
+ }
+ }
+}
+
+static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
+{
+ int y;
+ float scale_ratio = stbir_info->vertical_scale;
+ float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio;
+
+ STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
+
+ for (y = 0; y < stbir_info->output_h; y++)
+ {
+ float in_center_of_out = 0; // Center of the current out scanline in the in scanline space
+ int in_first_scanline = 0, in_last_scanline = 0;
+
+ stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
+
+ STBIR_ASSERT(in_last_scanline - in_first_scanline <= stbir_info->vertical_filter_pixel_width);
+
+ if (stbir_info->ring_buffer_begin_index >= 0)
+ {
+ // Get rid of whatever we don't need anymore.
+ while (in_first_scanline > stbir_info->ring_buffer_first_scanline)
+ {
+ if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
+ {
+ // We just popped the last scanline off the ring buffer.
+ // Reset it to the empty state.
+ stbir_info->ring_buffer_begin_index = -1;
+ stbir_info->ring_buffer_first_scanline = 0;
+ stbir_info->ring_buffer_last_scanline = 0;
+ break;
+ }
+ else
+ {
+ stbir_info->ring_buffer_first_scanline++;
+ stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->vertical_filter_pixel_width;
+ }
+ }
+ }
+
+ // Load in new ones.
+ if (stbir_info->ring_buffer_begin_index < 0)
+ stbir__decode_and_resample_upsample(stbir_info, in_first_scanline);
+
+ while (in_last_scanline > stbir_info->ring_buffer_last_scanline)
+ stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
+
+ // Now all buffers should be ready to write a row of vertical sampling.
+ stbir__resample_vertical_upsample(stbir_info, y, in_first_scanline, in_last_scanline, in_center_of_out);
+
+ STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h);
+ }
+}
+
+static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline)
+{
+ int output_stride_bytes = stbir_info->output_stride_bytes;
+ int channels = stbir_info->channels;
+ int alpha_channel = stbir_info->alpha_channel;
+ int type = stbir_info->type;
+ int colorspace = stbir_info->colorspace;
+ int output_w = stbir_info->output_w;
+ void* output_data = stbir_info->output_data;
+ int decode = STBIR__DECODE(type, colorspace);
+
+ float* ring_buffer = stbir_info->ring_buffer;
+ int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
+
+ if (stbir_info->ring_buffer_begin_index >= 0)
+ {
+ // Get rid of whatever we don't need anymore.
+ while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline)
+ {
+ if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h)
+ {
+ int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes;
+ float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length);
+ stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode);
+ STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h);
+ }
+
+ if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
+ {
+ // We just popped the last scanline off the ring buffer.
+ // Reset it to the empty state.
+ stbir_info->ring_buffer_begin_index = -1;
+ stbir_info->ring_buffer_first_scanline = 0;
+ stbir_info->ring_buffer_last_scanline = 0;
+ break;
+ }
+ else
+ {
+ stbir_info->ring_buffer_first_scanline++;
+ stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->vertical_filter_pixel_width;
+ }
+ }
+ }
+}
+
+static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
+{
+ int y;
+ float scale_ratio = stbir_info->vertical_scale;
+ int output_h = stbir_info->output_h;
+ float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio;
+ int pixel_margin = stbir_info->vertical_filter_pixel_margin;
+ int max_y = stbir_info->input_h + pixel_margin;
+
+ STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
+
+ for (y = -pixel_margin; y < max_y; y++)
+ {
+ float out_center_of_in; // Center of the current out scanline in the in scanline space
+ int out_first_scanline, out_last_scanline;
+
+ stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
+
+ STBIR_ASSERT(out_last_scanline - out_first_scanline <= stbir_info->vertical_filter_pixel_width);
+
+ if (out_last_scanline < 0 || out_first_scanline >= output_h)
+ continue;
+
+ stbir__empty_ring_buffer(stbir_info, out_first_scanline);
+
+ stbir__decode_and_resample_downsample(stbir_info, y);
+
+ // Load in new ones.
+ if (stbir_info->ring_buffer_begin_index < 0)
+ stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline);
+
+ while (out_last_scanline > stbir_info->ring_buffer_last_scanline)
+ stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
+
+ // Now the horizontal buffer is ready to write to all ring buffer rows.
+ stbir__resample_vertical_downsample(stbir_info, y, out_first_scanline, out_last_scanline, out_center_of_in);
+ }
+
+ stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
+}
+
+static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels)
+{
+ info->input_w = input_w;
+ info->input_h = input_h;
+ info->output_w = output_w;
+ info->output_h = output_h;
+ info->channels = channels;
+}
+
+static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform)
+{
+ info->s0 = s0;
+ info->t0 = t0;
+ info->s1 = s1;
+ info->t1 = t1;
+
+ if (transform)
+ {
+ info->horizontal_scale = transform[0];
+ info->vertical_scale = transform[1];
+ info->horizontal_shift = transform[2];
+ info->vertical_shift = transform[3];
+ }
+ else
+ {
+ info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
+ info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
+
+ info->horizontal_shift = s0 * info->output_w / (s1 - s0);
+ info->vertical_shift = t0 * info->output_h / (t1 - t0);
+ }
+}
+
+static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter)
+{
+ if (h_filter == 0)
+ h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
+ if (v_filter == 0)
+ v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
+ info->horizontal_filter = h_filter;
+ info->vertical_filter = v_filter;
+}
+
+static stbir_uint32 stbir__calculate_memory(stbir__info *info)
+{
+ int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
+ int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale);
+
+ info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
+ info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h);
+
+ info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
+ info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float);
+ info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
+ info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float);
+ info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float);
+ info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float);
+ info->ring_buffer_size = info->output_w * info->channels * filter_height * sizeof(float);
+ info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
+
+ STBIR_ASSERT(info->horizontal_filter != 0);
+ STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
+ STBIR_ASSERT(info->vertical_filter != 0);
+ STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
+
+ if (stbir__use_height_upsampling(info))
+ // The horizontal buffer is for when we're downsampling the height and we
+ // can't output the result of sampling the decode buffer directly into the
+ // ring buffers.
+ info->horizontal_buffer_size = 0;
+ else
+ // The encode buffer is to retain precision in the height upsampling method
+ // and isn't used when height downsampling.
+ info->encode_buffer_size = 0;
+
+ return info->horizontal_contributors_size + info->horizontal_coefficients_size
+ + info->vertical_contributors_size + info->vertical_coefficients_size
+ + info->decode_buffer_size + info->horizontal_buffer_size
+ + info->ring_buffer_size + info->encode_buffer_size;
+}
+
+static int stbir__resize_allocated(stbir__info *info,
+ const void* input_data, int input_stride_in_bytes,
+ void* output_data, int output_stride_in_bytes,
+ int alpha_channel, stbir_uint32 flags, stbir_datatype type,
+ stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace,
+ void* tempmem, size_t tempmem_size_in_bytes)
+{
+ size_t memory_required = stbir__calculate_memory(info);
+
+ int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type];
+ int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type];
+
+#ifdef STBIR_DEBUG_OVERWRITE_TEST
+#define OVERWRITE_ARRAY_SIZE 8
+ unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE];
+ unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE];
+ unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE];
+ unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE];
+
+ size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type];
+ memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
+ memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE);
+ memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
+ memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE);
+#endif
+
+ STBIR_ASSERT(info->channels >= 0);
+ STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS);
+
+ if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS)
+ return 0;
+
+ STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
+ STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
+
+ if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
+ return 0;
+ if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
+ return 0;
+
+ if (alpha_channel < 0)
+ flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED;
+
+ if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
+ STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels);
+
+ if (alpha_channel >= info->channels)
+ return 0;
+
+ STBIR_ASSERT(tempmem);
+
+ if (!tempmem)
+ return 0;
+
+ STBIR_ASSERT(tempmem_size_in_bytes >= memory_required);
+
+ if (tempmem_size_in_bytes < memory_required)
+ return 0;
+
+ memset(tempmem, 0, tempmem_size_in_bytes);
+
+ info->input_data = input_data;
+ info->input_stride_bytes = width_stride_input;
+
+ info->output_data = output_data;
+ info->output_stride_bytes = width_stride_output;
+
+ info->alpha_channel = alpha_channel;
+ info->flags = flags;
+ info->type = type;
+ info->edge_horizontal = edge_horizontal;
+ info->edge_vertical = edge_vertical;
+ info->colorspace = colorspace;
+
+ info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
+ info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale );
+ info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale);
+ info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale );
+ info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
+ info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale );
+
+ info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float);
+ info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2;
+
+#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size)
+
+ info->horizontal_contributors = (stbir__contributors *) tempmem;
+ info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float);
+ info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors);
+ info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float);
+ info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float);
+
+ if (stbir__use_height_upsampling(info))
+ {
+ info->horizontal_buffer = NULL;
+ info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
+ info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float);
+
+ STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
+ }
+ else
+ {
+ info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
+ info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float);
+ info->encode_buffer = NULL;
+
+ STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
+ }
+
+#undef STBIR__NEXT_MEMPTR
+
+ // This signals that the ring buffer is empty
+ info->ring_buffer_begin_index = -1;
+
+ stbir__calculate_filters(info, info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
+ stbir__calculate_filters(info, info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
+
+ STBIR_PROGRESS_REPORT(0);
+
+ if (stbir__use_height_upsampling(info))
+ stbir__buffer_loop_upsample(info);
+ else
+ stbir__buffer_loop_downsample(info);
+
+ STBIR_PROGRESS_REPORT(1);
+
+#ifdef STBIR_DEBUG_OVERWRITE_TEST
+ STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
+ STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
+ STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
+ STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
+#endif
+
+ return 1;
+}
+
+
+static int stbir__resize_arbitrary(
+ void *alloc_context,
+ const void* input_data, int input_w, int input_h, int input_stride_in_bytes,
+ void* output_data, int output_w, int output_h, int output_stride_in_bytes,
+ float s0, float t0, float s1, float t1, float *transform,
+ int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type,
+ stbir_filter h_filter, stbir_filter v_filter,
+ stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace)
+{
+ stbir__info info;
+ int result;
+ size_t memory_required;
+ void* extra_memory;
+
+ stbir__setup(&info, input_w, input_h, output_w, output_h, channels);
+ stbir__calculate_transform(&info, s0,t0,s1,t1,transform);
+ stbir__choose_filter(&info, h_filter, v_filter);
+ memory_required = stbir__calculate_memory(&info);
+ extra_memory = STBIR_MALLOC(memory_required, alloc_context);
+
+ if (!extra_memory)
+ return 0;
+
+ result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes,
+ output_data, output_stride_in_bytes,
+ alpha_channel, flags, type,
+ edge_horizontal, edge_vertical,
+ colorspace, extra_memory, memory_required);
+
+ STBIR_FREE(extra_memory, alloc_context);
+
+ return result;
+}
+
+STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels)
+{
+ return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
+ STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
+}
+
+STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels)
+{
+ return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
+ STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
+}
+
+STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags)
+{
+ return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
+ STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB);
+}
+
+STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode)
+{
+ return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
+ edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB);
+}
+
+STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
+ void *alloc_context)
+{
+ return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter,
+ edge_wrap_mode, edge_wrap_mode, space);
+}
+
+STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
+ void *alloc_context)
+{
+ return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter,
+ edge_wrap_mode, edge_wrap_mode, space);
+}
+
+
+STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
+ void *alloc_context)
+{
+ return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter,
+ edge_wrap_mode, edge_wrap_mode, space);
+}
+
+
+STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ stbir_datatype datatype,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
+ stbir_filter filter_horizontal, stbir_filter filter_vertical,
+ stbir_colorspace space, void *alloc_context)
+{
+ return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
+ edge_mode_horizontal, edge_mode_vertical, space);
+}
+
+
+STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ stbir_datatype datatype,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
+ stbir_filter filter_horizontal, stbir_filter filter_vertical,
+ stbir_colorspace space, void *alloc_context,
+ float x_scale, float y_scale,
+ float x_offset, float y_offset)
+{
+ float transform[4];
+ transform[0] = x_scale;
+ transform[1] = y_scale;
+ transform[2] = x_offset;
+ transform[3] = y_offset;
+ return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
+ edge_mode_horizontal, edge_mode_vertical, space);
+}
+
+STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ stbir_datatype datatype,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
+ stbir_filter filter_horizontal, stbir_filter filter_vertical,
+ stbir_colorspace space, void *alloc_context,
+ float s0, float t0, float s1, float t1)
+{
+ return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
+ edge_mode_horizontal, edge_mode_vertical, space);
+}
+
+#endif // STB_IMAGE_RESIZE_IMPLEMENTATION
diff --git a/src/external/stb_image_write.h b/src/external/stb_image_write.h
new file mode 100644
index 00000000..ae9180b0
--- /dev/null
+++ b/src/external/stb_image_write.h
@@ -0,0 +1,1049 @@
+/* stb_image_write - v1.03 - public domain - http://nothings.org/stb/stb_image_write.h
+ writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
+ no warranty implied; use at your own risk
+
+ Before #including,
+
+ #define STB_IMAGE_WRITE_IMPLEMENTATION
+
+ in the file that you want to have the implementation.
+
+ Will probably not work correctly with strict-aliasing optimizations.
+
+ABOUT:
+
+ This header file is a library for writing images to C stdio. It could be
+ adapted to write to memory or a general streaming interface; let me know.
+
+ The PNG output is not optimal; it is 20-50% larger than the file
+ written by a decent optimizing implementation. This library is designed
+ for source code compactness and simplicity, not optimal image file size
+ or run-time performance.
+
+BUILDING:
+
+ You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
+ You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
+ malloc,realloc,free.
+ You can define STBIW_MEMMOVE() to replace memmove()
+
+USAGE:
+
+ There are four functions, one for each image file format:
+
+ int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
+ int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
+ int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
+ int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
+
+ There are also four equivalent functions that use an arbitrary write function. You are
+ expected to open/close your file-equivalent before and after calling these:
+
+ int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
+ int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
+ int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
+ int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
+
+ where the callback is:
+ void stbi_write_func(void *context, void *data, int size);
+
+ You can define STBI_WRITE_NO_STDIO to disable the file variant of these
+ functions, so the library will not use stdio.h at all. However, this will
+ also disable HDR writing, because it requires stdio for formatted output.
+
+ Each function returns 0 on failure and non-0 on success.
+
+ The functions create an image file defined by the parameters. The image
+ is a rectangle of pixels stored from left-to-right, top-to-bottom.
+ Each pixel contains 'comp' channels of data stored interleaved with 8-bits
+ per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
+ monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
+ The *data pointer points to the first byte of the top-left-most pixel.
+ For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
+ a row of pixels to the first byte of the next row of pixels.
+
+ PNG creates output files with the same number of components as the input.
+ The BMP format expands Y to RGB in the file format and does not
+ output alpha.
+
+ PNG supports writing rectangles of data even when the bytes storing rows of
+ data are not consecutive in memory (e.g. sub-rectangles of a larger image),
+ by supplying the stride between the beginning of adjacent rows. The other
+ formats do not. (Thus you cannot write a native-format BMP through the BMP
+ writer, both because it is in BGR order and because it may have padding
+ at the end of the line.)
+
+ HDR expects linear float data. Since the format is always 32-bit rgb(e)
+ data, alpha (if provided) is discarded, and for monochrome data it is
+ replicated across all three channels.
+
+ TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
+ data, set the global variable 'stbi_write_tga_with_rle' to 0.
+
+CREDITS:
+
+ PNG/BMP/TGA
+ Sean Barrett
+ HDR
+ Baldur Karlsson
+ TGA monochrome:
+ Jean-Sebastien Guay
+ misc enhancements:
+ Tim Kelsey
+ TGA RLE
+ Alan Hickman
+ initial file IO callback implementation
+ Emmanuel Julien
+ bugfixes:
+ github:Chribba
+ Guillaume Chereau
+ github:jry2
+ github:romigrou
+ Sergio Gonzalez
+ Jonas Karlsson
+ Filip Wasil
+ Thatcher Ulrich
+ github:poppolopoppo
+
+LICENSE
+
+This software is dual-licensed to the public domain and under the following
+license: you are granted a perpetual, irrevocable license to copy, modify,
+publish, and distribute this file as you see fit.
+
+*/
+
+#ifndef INCLUDE_STB_IMAGE_WRITE_H
+#define INCLUDE_STB_IMAGE_WRITE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef STB_IMAGE_WRITE_STATIC
+#define STBIWDEF static
+#else
+#define STBIWDEF extern
+extern int stbi_write_tga_with_rle;
+#endif
+
+#ifndef STBI_WRITE_NO_STDIO
+STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
+STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
+STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
+STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
+#endif
+
+typedef void stbi_write_func(void *context, void *data, int size);
+
+STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
+STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
+STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
+STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif//INCLUDE_STB_IMAGE_WRITE_H
+
+#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
+
+#ifdef _WIN32
+ #ifndef _CRT_SECURE_NO_WARNINGS
+ #define _CRT_SECURE_NO_WARNINGS
+ #endif
+ #ifndef _CRT_NONSTDC_NO_DEPRECATE
+ #define _CRT_NONSTDC_NO_DEPRECATE
+ #endif
+#endif
+
+#ifndef STBI_WRITE_NO_STDIO
+#include <stdio.h>
+#endif // STBI_WRITE_NO_STDIO
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
+// ok
+#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
+// ok
+#else
+#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
+#endif
+
+#ifndef STBIW_MALLOC
+#define STBIW_MALLOC(sz) malloc(sz)
+#define STBIW_REALLOC(p,newsz) realloc(p,newsz)
+#define STBIW_FREE(p) free(p)
+#endif
+
+#ifndef STBIW_REALLOC_SIZED
+#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
+#endif
+
+
+#ifndef STBIW_MEMMOVE
+#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
+#endif
+
+
+#ifndef STBIW_ASSERT
+#include <assert.h>
+#define STBIW_ASSERT(x) assert(x)
+#endif
+
+#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
+
+typedef struct
+{
+ stbi_write_func *func;
+ void *context;
+} stbi__write_context;
+
+// initialize a callback-based context
+static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)
+{
+ s->func = c;
+ s->context = context;
+}
+
+#ifndef STBI_WRITE_NO_STDIO
+
+static void stbi__stdio_write(void *context, void *data, int size)
+{
+ fwrite(data,1,size,(FILE*) context);
+}
+
+static int stbi__start_write_file(stbi__write_context *s, const char *filename)
+{
+ FILE *f = fopen(filename, "wb");
+ stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
+ return f != NULL;
+}
+
+static void stbi__end_write_file(stbi__write_context *s)
+{
+ fclose((FILE *)s->context);
+}
+
+#endif // !STBI_WRITE_NO_STDIO
+
+typedef unsigned int stbiw_uint32;
+typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
+
+#ifdef STB_IMAGE_WRITE_STATIC
+static int stbi_write_tga_with_rle = 1;
+#else
+int stbi_write_tga_with_rle = 1;
+#endif
+
+static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
+{
+ while (*fmt) {
+ switch (*fmt++) {
+ case ' ': break;
+ case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
+ s->func(s->context,&x,1);
+ break; }
+ case '2': { int x = va_arg(v,int);
+ unsigned char b[2];
+ b[0] = STBIW_UCHAR(x);
+ b[1] = STBIW_UCHAR(x>>8);
+ s->func(s->context,b,2);
+ break; }
+ case '4': { stbiw_uint32 x = va_arg(v,int);
+ unsigned char b[4];
+ b[0]=STBIW_UCHAR(x);
+ b[1]=STBIW_UCHAR(x>>8);
+ b[2]=STBIW_UCHAR(x>>16);
+ b[3]=STBIW_UCHAR(x>>24);
+ s->func(s->context,b,4);
+ break; }
+ default:
+ STBIW_ASSERT(0);
+ return;
+ }
+ }
+}
+
+static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
+{
+ va_list v;
+ va_start(v, fmt);
+ stbiw__writefv(s, fmt, v);
+ va_end(v);
+}
+
+static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
+{
+ unsigned char arr[3];
+ arr[0] = a, arr[1] = b, arr[2] = c;
+ s->func(s->context, arr, 3);
+}
+
+static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)
+{
+ unsigned char bg[3] = { 255, 0, 255}, px[3];
+ int k;
+
+ if (write_alpha < 0)
+ s->func(s->context, &d[comp - 1], 1);
+
+ switch (comp) {
+ case 1:
+ s->func(s->context,d,1);
+ break;
+ case 2:
+ if (expand_mono)
+ stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
+ else
+ s->func(s->context, d, 1); // monochrome TGA
+ break;
+ case 4:
+ if (!write_alpha) {
+ // composite against pink background
+ for (k = 0; k < 3; ++k)
+ px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
+ stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
+ break;
+ }
+ /* FALLTHROUGH */
+ case 3:
+ stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
+ break;
+ }
+ if (write_alpha > 0)
+ s->func(s->context, &d[comp - 1], 1);
+}
+
+static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
+{
+ stbiw_uint32 zero = 0;
+ int i,j, j_end;
+
+ if (y <= 0)
+ return;
+
+ if (vdir < 0)
+ j_end = -1, j = y-1;
+ else
+ j_end = y, j = 0;
+
+ for (; j != j_end; j += vdir) {
+ for (i=0; i < x; ++i) {
+ unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
+ stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
+ }
+ s->func(s->context, &zero, scanline_pad);
+ }
+}
+
+static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
+{
+ if (y < 0 || x < 0) {
+ return 0;
+ } else {
+ va_list v;
+ va_start(v, fmt);
+ stbiw__writefv(s, fmt, v);
+ va_end(v);
+ stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);
+ return 1;
+ }
+}
+
+static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
+{
+ int pad = (-x*3) & 3;
+ return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
+ "11 4 22 4" "4 44 22 444444",
+ 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
+ 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
+}
+
+STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
+{
+ stbi__write_context s;
+ stbi__start_write_callbacks(&s, func, context);
+ return stbi_write_bmp_core(&s, x, y, comp, data);
+}
+
+#ifndef STBI_WRITE_NO_STDIO
+STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
+{
+ stbi__write_context s;
+ if (stbi__start_write_file(&s,filename)) {
+ int r = stbi_write_bmp_core(&s, x, y, comp, data);
+ stbi__end_write_file(&s);
+ return r;
+ } else
+ return 0;
+}
+#endif //!STBI_WRITE_NO_STDIO
+
+static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
+{
+ int has_alpha = (comp == 2 || comp == 4);
+ int colorbytes = has_alpha ? comp-1 : comp;
+ int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
+
+ if (y < 0 || x < 0)
+ return 0;
+
+ if (!stbi_write_tga_with_rle) {
+ return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
+ "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
+ } else {
+ int i,j,k;
+
+ stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);
+
+ for (j = y - 1; j >= 0; --j) {
+ unsigned char *row = (unsigned char *) data + j * x * comp;
+ int len;
+
+ for (i = 0; i < x; i += len) {
+ unsigned char *begin = row + i * comp;
+ int diff = 1;
+ len = 1;
+
+ if (i < x - 1) {
+ ++len;
+ diff = memcmp(begin, row + (i + 1) * comp, comp);
+ if (diff) {
+ const unsigned char *prev = begin;
+ for (k = i + 2; k < x && len < 128; ++k) {
+ if (memcmp(prev, row + k * comp, comp)) {
+ prev += comp;
+ ++len;
+ } else {
+ --len;
+ break;
+ }
+ }
+ } else {
+ for (k = i + 2; k < x && len < 128; ++k) {
+ if (!memcmp(begin, row + k * comp, comp)) {
+ ++len;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ if (diff) {
+ unsigned char header = STBIW_UCHAR(len - 1);
+ s->func(s->context, &header, 1);
+ for (k = 0; k < len; ++k) {
+ stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
+ }
+ } else {
+ unsigned char header = STBIW_UCHAR(len - 129);
+ s->func(s->context, &header, 1);
+ stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
+{
+ stbi__write_context s;
+ stbi__start_write_callbacks(&s, func, context);
+ return stbi_write_tga_core(&s, x, y, comp, (void *) data);
+}
+
+#ifndef STBI_WRITE_NO_STDIO
+int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
+{
+ stbi__write_context s;
+ if (stbi__start_write_file(&s,filename)) {
+ int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
+ stbi__end_write_file(&s);
+ return r;
+ } else
+ return 0;
+}
+#endif
+
+// *************************************************************************************************
+// Radiance RGBE HDR writer
+// by Baldur Karlsson
+
+#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
+
+void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
+{
+ int exponent;
+ float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
+
+ if (maxcomp < 1e-32f) {
+ rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
+ } else {
+ float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
+
+ rgbe[0] = (unsigned char)(linear[0] * normalize);
+ rgbe[1] = (unsigned char)(linear[1] * normalize);
+ rgbe[2] = (unsigned char)(linear[2] * normalize);
+ rgbe[3] = (unsigned char)(exponent + 128);
+ }
+}
+
+void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
+{
+ unsigned char lengthbyte = STBIW_UCHAR(length+128);
+ STBIW_ASSERT(length+128 <= 255);
+ s->func(s->context, &lengthbyte, 1);
+ s->func(s->context, &databyte, 1);
+}
+
+void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
+{
+ unsigned char lengthbyte = STBIW_UCHAR(length);
+ STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
+ s->func(s->context, &lengthbyte, 1);
+ s->func(s->context, data, length);
+}
+
+void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)
+{
+ unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
+ unsigned char rgbe[4];
+ float linear[3];
+ int x;
+
+ scanlineheader[2] = (width&0xff00)>>8;
+ scanlineheader[3] = (width&0x00ff);
+
+ /* skip RLE for images too small or large */
+ if (width < 8 || width >= 32768) {
+ for (x=0; x < width; x++) {
+ switch (ncomp) {
+ case 4: /* fallthrough */
+ case 3: linear[2] = scanline[x*ncomp + 2];
+ linear[1] = scanline[x*ncomp + 1];
+ linear[0] = scanline[x*ncomp + 0];
+ break;
+ default:
+ linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
+ break;
+ }
+ stbiw__linear_to_rgbe(rgbe, linear);
+ s->func(s->context, rgbe, 4);
+ }
+ } else {
+ int c,r;
+ /* encode into scratch buffer */
+ for (x=0; x < width; x++) {
+ switch(ncomp) {
+ case 4: /* fallthrough */
+ case 3: linear[2] = scanline[x*ncomp + 2];
+ linear[1] = scanline[x*ncomp + 1];
+ linear[0] = scanline[x*ncomp + 0];
+ break;
+ default:
+ linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
+ break;
+ }
+ stbiw__linear_to_rgbe(rgbe, linear);
+ scratch[x + width*0] = rgbe[0];
+ scratch[x + width*1] = rgbe[1];
+ scratch[x + width*2] = rgbe[2];
+ scratch[x + width*3] = rgbe[3];
+ }
+
+ s->func(s->context, scanlineheader, 4);
+
+ /* RLE each component separately */
+ for (c=0; c < 4; c++) {
+ unsigned char *comp = &scratch[width*c];
+
+ x = 0;
+ while (x < width) {
+ // find first run
+ r = x;
+ while (r+2 < width) {
+ if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
+ break;
+ ++r;
+ }
+ if (r+2 >= width)
+ r = width;
+ // dump up to first run
+ while (x < r) {
+ int len = r-x;
+ if (len > 128) len = 128;
+ stbiw__write_dump_data(s, len, &comp[x]);
+ x += len;
+ }
+ // if there's a run, output it
+ if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
+ // find next byte after run
+ while (r < width && comp[r] == comp[x])
+ ++r;
+ // output run up to r
+ while (x < r) {
+ int len = r-x;
+ if (len > 127) len = 127;
+ stbiw__write_run_data(s, len, comp[x]);
+ x += len;
+ }
+ }
+ }
+ }
+ }
+}
+
+static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)
+{
+ if (y <= 0 || x <= 0 || data == NULL)
+ return 0;
+ else {
+ // Each component is stored separately. Allocate scratch space for full output scanline.
+ unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
+ int i, len;
+ char buffer[128];
+ char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
+ s->func(s->context, header, sizeof(header)-1);
+
+ len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
+ s->func(s->context, buffer, len);
+
+ for(i=0; i < y; i++)
+ stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x);
+ STBIW_FREE(scratch);
+ return 1;
+ }
+}
+
+int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
+{
+ stbi__write_context s;
+ stbi__start_write_callbacks(&s, func, context);
+ return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
+}
+
+#ifndef STBI_WRITE_NO_STDIO
+int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
+{
+ stbi__write_context s;
+ if (stbi__start_write_file(&s,filename)) {
+ int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
+ stbi__end_write_file(&s);
+ return r;
+ } else
+ return 0;
+}
+#endif // STBI_WRITE_NO_STDIO
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PNG writer
+//
+
+// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
+#define stbiw__sbraw(a) ((int *) (a) - 2)
+#define stbiw__sbm(a) stbiw__sbraw(a)[0]
+#define stbiw__sbn(a) stbiw__sbraw(a)[1]
+
+#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
+#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
+#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
+
+#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
+#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
+#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
+
+static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
+{
+ int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
+ void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
+ STBIW_ASSERT(p);
+ if (p) {
+ if (!*arr) ((int *) p)[1] = 0;
+ *arr = (void *) ((int *) p + 2);
+ stbiw__sbm(*arr) = m;
+ }
+ return *arr;
+}
+
+static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
+{
+ while (*bitcount >= 8) {
+ stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
+ *bitbuffer >>= 8;
+ *bitcount -= 8;
+ }
+ return data;
+}
+
+static int stbiw__zlib_bitrev(int code, int codebits)
+{
+ int res=0;
+ while (codebits--) {
+ res = (res << 1) | (code & 1);
+ code >>= 1;
+ }
+ return res;
+}
+
+static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
+{
+ int i;
+ for (i=0; i < limit && i < 258; ++i)
+ if (a[i] != b[i]) break;
+ return i;
+}
+
+static unsigned int stbiw__zhash(unsigned char *data)
+{
+ stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 4;
+ hash += hash >> 17;
+ hash ^= hash << 25;
+ hash += hash >> 6;
+ return hash;
+}
+
+#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
+#define stbiw__zlib_add(code,codebits) \
+ (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
+#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
+// default huffman tables
+#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
+#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
+#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
+#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
+#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))
+#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
+
+#define stbiw__ZHASH 16384
+
+unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
+{
+ static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
+ static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
+ static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
+ static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
+ unsigned int bitbuf=0;
+ int i,j, bitcount=0;
+ unsigned char *out = NULL;
+ unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
+ if (quality < 5) quality = 5;
+
+ stbiw__sbpush(out, 0x78); // DEFLATE 32K window
+ stbiw__sbpush(out, 0x5e); // FLEVEL = 1
+ stbiw__zlib_add(1,1); // BFINAL = 1
+ stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
+
+ for (i=0; i < stbiw__ZHASH; ++i)
+ hash_table[i] = NULL;
+
+ i=0;
+ while (i < data_len-3) {
+ // hash next 3 bytes of data to be compressed
+ int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
+ unsigned char *bestloc = 0;
+ unsigned char **hlist = hash_table[h];
+ int n = stbiw__sbcount(hlist);
+ for (j=0; j < n; ++j) {
+ if (hlist[j]-data > i-32768) { // if entry lies within window
+ int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
+ if (d >= best) best=d,bestloc=hlist[j];
+ }
+ }
+ // when hash table entry is too long, delete half the entries
+ if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
+ STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
+ stbiw__sbn(hash_table[h]) = quality;
+ }
+ stbiw__sbpush(hash_table[h],data+i);
+
+ if (bestloc) {
+ // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
+ h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
+ hlist = hash_table[h];
+ n = stbiw__sbcount(hlist);
+ for (j=0; j < n; ++j) {
+ if (hlist[j]-data > i-32767) {
+ int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
+ if (e > best) { // if next match is better, bail on current match
+ bestloc = NULL;
+ break;
+ }
+ }
+ }
+ }
+
+ if (bestloc) {
+ int d = (int) (data+i - bestloc); // distance back
+ STBIW_ASSERT(d <= 32767 && best <= 258);
+ for (j=0; best > lengthc[j+1]-1; ++j);
+ stbiw__zlib_huff(j+257);
+ if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
+ for (j=0; d > distc[j+1]-1; ++j);
+ stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
+ if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
+ i += best;
+ } else {
+ stbiw__zlib_huffb(data[i]);
+ ++i;
+ }
+ }
+ // write out final bytes
+ for (;i < data_len; ++i)
+ stbiw__zlib_huffb(data[i]);
+ stbiw__zlib_huff(256); // end of block
+ // pad with 0 bits to byte boundary
+ while (bitcount)
+ stbiw__zlib_add(0,1);
+
+ for (i=0; i < stbiw__ZHASH; ++i)
+ (void) stbiw__sbfree(hash_table[i]);
+ STBIW_FREE(hash_table);
+
+ {
+ // compute adler32 on input
+ unsigned int s1=1, s2=0;
+ int blocklen = (int) (data_len % 5552);
+ j=0;
+ while (j < data_len) {
+ for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
+ s1 %= 65521, s2 %= 65521;
+ j += blocklen;
+ blocklen = 5552;
+ }
+ stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
+ stbiw__sbpush(out, STBIW_UCHAR(s2));
+ stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
+ stbiw__sbpush(out, STBIW_UCHAR(s1));
+ }
+ *out_len = stbiw__sbn(out);
+ // make returned pointer freeable
+ STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
+ return (unsigned char *) stbiw__sbraw(out);
+}
+
+static unsigned int stbiw__crc32(unsigned char *buffer, int len)
+{
+ static unsigned int crc_table[256] =
+ {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+ };
+
+ unsigned int crc = ~0u;
+ int i;
+ for (i=0; i < len; ++i)
+ crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
+ return ~crc;
+}
+
+#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)
+#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
+#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
+
+static void stbiw__wpcrc(unsigned char **data, int len)
+{
+ unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
+ stbiw__wp32(*data, crc);
+}
+
+static unsigned char stbiw__paeth(int a, int b, int c)
+{
+ int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
+ if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
+ if (pb <= pc) return STBIW_UCHAR(b);
+ return STBIW_UCHAR(c);
+}
+
+unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
+{
+ int ctype[5] = { -1, 0, 4, 2, 6 };
+ unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
+ unsigned char *out,*o, *filt, *zlib;
+ signed char *line_buffer;
+ int i,j,k,p,zlen;
+
+ if (stride_bytes == 0)
+ stride_bytes = x * n;
+
+ filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
+ line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
+ for (j=0; j < y; ++j) {
+ static int mapping[] = { 0,1,2,3,4 };
+ static int firstmap[] = { 0,1,0,5,6 };
+ int *mymap = j ? mapping : firstmap;
+ int best = 0, bestval = 0x7fffffff;
+ for (p=0; p < 2; ++p) {
+ for (k= p?best:0; k < 5; ++k) {
+ int type = mymap[k],est=0;
+ unsigned char *z = pixels + stride_bytes*j;
+ for (i=0; i < n; ++i)
+ switch (type) {
+ case 0: line_buffer[i] = z[i]; break;
+ case 1: line_buffer[i] = z[i]; break;
+ case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
+ case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
+ case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
+ case 5: line_buffer[i] = z[i]; break;
+ case 6: line_buffer[i] = z[i]; break;
+ }
+ for (i=n; i < x*n; ++i) {
+ switch (type) {
+ case 0: line_buffer[i] = z[i]; break;
+ case 1: line_buffer[i] = z[i] - z[i-n]; break;
+ case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
+ case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
+ case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
+ case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
+ case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
+ }
+ }
+ if (p) break;
+ for (i=0; i < x*n; ++i)
+ est += abs((signed char) line_buffer[i]);
+ if (est < bestval) { bestval = est; best = k; }
+ }
+ }
+ // when we get here, best contains the filter type, and line_buffer contains the data
+ filt[j*(x*n+1)] = (unsigned char) best;
+ STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
+ }
+ STBIW_FREE(line_buffer);
+ zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
+ STBIW_FREE(filt);
+ if (!zlib) return 0;
+
+ // each tag requires 12 bytes of overhead
+ out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
+ if (!out) return 0;
+ *out_len = 8 + 12+13 + 12+zlen + 12;
+
+ o=out;
+ STBIW_MEMMOVE(o,sig,8); o+= 8;
+ stbiw__wp32(o, 13); // header length
+ stbiw__wptag(o, "IHDR");
+ stbiw__wp32(o, x);
+ stbiw__wp32(o, y);
+ *o++ = 8;
+ *o++ = STBIW_UCHAR(ctype[n]);
+ *o++ = 0;
+ *o++ = 0;
+ *o++ = 0;
+ stbiw__wpcrc(&o,13);
+
+ stbiw__wp32(o, zlen);
+ stbiw__wptag(o, "IDAT");
+ STBIW_MEMMOVE(o, zlib, zlen);
+ o += zlen;
+ STBIW_FREE(zlib);
+ stbiw__wpcrc(&o, zlen);
+
+ stbiw__wp32(o,0);
+ stbiw__wptag(o, "IEND");
+ stbiw__wpcrc(&o,0);
+
+ STBIW_ASSERT(o == out + *out_len);
+
+ return out;
+}
+
+#ifndef STBI_WRITE_NO_STDIO
+STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
+{
+ FILE *f;
+ int len;
+ unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
+ if (png == NULL) return 0;
+ f = fopen(filename, "wb");
+ if (!f) { STBIW_FREE(png); return 0; }
+ fwrite(png, 1, len, f);
+ fclose(f);
+ STBIW_FREE(png);
+ return 1;
+}
+#endif
+
+STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)
+{
+ int len;
+ unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
+ if (png == NULL) return 0;
+ func(context, png, len);
+ STBIW_FREE(png);
+ return 1;
+}
+
+#endif // STB_IMAGE_WRITE_IMPLEMENTATION
+
+/* Revision history
+ 1.02 (2016-04-02)
+ avoid allocating large structures on the stack
+ 1.01 (2016-01-16)
+ STBIW_REALLOC_SIZED: support allocators with no realloc support
+ avoid race-condition in crc initialization
+ minor compile issues
+ 1.00 (2015-09-14)
+ installable file IO function
+ 0.99 (2015-09-13)
+ warning fixes; TGA rle support
+ 0.98 (2015-04-08)
+ added STBIW_MALLOC, STBIW_ASSERT etc
+ 0.97 (2015-01-18)
+ fixed HDR asserts, rewrote HDR rle logic
+ 0.96 (2015-01-17)
+ add HDR output
+ fix monochrome BMP
+ 0.95 (2014-08-17)
+ add monochrome TGA output
+ 0.94 (2014-05-31)
+ rename private functions to avoid conflicts with stb_image.h
+ 0.93 (2014-05-27)
+ warning fixes
+ 0.92 (2010-08-01)
+ casts to unsigned char to fix warnings
+ 0.91 (2010-07-17)
+ first public release
+ 0.90 first internal release
+*/
diff --git a/src/external/stb_rect_pack.h b/src/external/stb_rect_pack.h
new file mode 100644
index 00000000..c75527da
--- /dev/null
+++ b/src/external/stb_rect_pack.h
@@ -0,0 +1,583 @@
+// stb_rect_pack.h - v0.10 - public domain - rectangle packing
+// Sean Barrett 2014
+//
+// Useful for e.g. packing rectangular textures into an atlas.
+// Does not do rotation.
+//
+// Not necessarily the awesomest packing method, but better than
+// the totally naive one in stb_truetype (which is primarily what
+// this is meant to replace).
+//
+// Has only had a few tests run, may have issues.
+//
+// More docs to come.
+//
+// No memory allocations; uses qsort() and assert() from stdlib.
+// Can override those by defining STBRP_SORT and STBRP_ASSERT.
+//
+// This library currently uses the Skyline Bottom-Left algorithm.
+//
+// Please note: better rectangle packers are welcome! Please
+// implement them to the same API, but with a different init
+// function.
+//
+// Credits
+//
+// Library
+// Sean Barrett
+// Minor features
+// Martins Mozeiko
+// Bugfixes / warning fixes
+// Jeremy Jaussaud
+//
+// Version history:
+//
+// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
+// 0.09 (2016-08-27) fix compiler warnings
+// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
+// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
+// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
+// 0.05: added STBRP_ASSERT to allow replacing assert
+// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
+// 0.01: initial release
+//
+// LICENSE
+//
+// This software is dual-licensed to the public domain and under the following
+// license: you are granted a perpetual, irrevocable license to copy, modify,
+// publish, and distribute this file as you see fit.
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// INCLUDE SECTION
+//
+
+#ifndef STB_INCLUDE_STB_RECT_PACK_H
+#define STB_INCLUDE_STB_RECT_PACK_H
+
+#define STB_RECT_PACK_VERSION 1
+
+#ifdef STBRP_STATIC
+#define STBRP_DEF static
+#else
+#define STBRP_DEF extern
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct stbrp_context stbrp_context;
+typedef struct stbrp_node stbrp_node;
+typedef struct stbrp_rect stbrp_rect;
+
+#ifdef STBRP_LARGE_RECTS
+typedef int stbrp_coord;
+#else
+typedef unsigned short stbrp_coord;
+#endif
+
+STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
+// Assign packed locations to rectangles. The rectangles are of type
+// 'stbrp_rect' defined below, stored in the array 'rects', and there
+// are 'num_rects' many of them.
+//
+// Rectangles which are successfully packed have the 'was_packed' flag
+// set to a non-zero value and 'x' and 'y' store the minimum location
+// on each axis (i.e. bottom-left in cartesian coordinates, top-left
+// if you imagine y increasing downwards). Rectangles which do not fit
+// have the 'was_packed' flag set to 0.
+//
+// You should not try to access the 'rects' array from another thread
+// while this function is running, as the function temporarily reorders
+// the array while it executes.
+//
+// To pack into another rectangle, you need to call stbrp_init_target
+// again. To continue packing into the same rectangle, you can call
+// this function again. Calling this multiple times with multiple rect
+// arrays will probably produce worse packing results than calling it
+// a single time with the full rectangle array, but the option is
+// available.
+
+struct stbrp_rect
+{
+ // reserved for your use:
+ int id;
+
+ // input:
+ stbrp_coord w, h;
+
+ // output:
+ stbrp_coord x, y;
+ int was_packed; // non-zero if valid packing
+
+}; // 16 bytes, nominally
+
+
+STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
+// Initialize a rectangle packer to:
+// pack a rectangle that is 'width' by 'height' in dimensions
+// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
+//
+// You must call this function every time you start packing into a new target.
+//
+// There is no "shutdown" function. The 'nodes' memory must stay valid for
+// the following stbrp_pack_rects() call (or calls), but can be freed after
+// the call (or calls) finish.
+//
+// Note: to guarantee best results, either:
+// 1. make sure 'num_nodes' >= 'width'
+// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
+//
+// If you don't do either of the above things, widths will be quantized to multiples
+// of small integers to guarantee the algorithm doesn't run out of temporary storage.
+//
+// If you do #2, then the non-quantized algorithm will be used, but the algorithm
+// may run out of temporary storage and be unable to pack some rectangles.
+
+STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
+// Optionally call this function after init but before doing any packing to
+// change the handling of the out-of-temp-memory scenario, described above.
+// If you call init again, this will be reset to the default (false).
+
+
+STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
+// Optionally select which packing heuristic the library should use. Different
+// heuristics will produce better/worse results for different data sets.
+// If you call init again, this will be reset to the default.
+
+enum
+{
+ STBRP_HEURISTIC_Skyline_default=0,
+ STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
+ STBRP_HEURISTIC_Skyline_BF_sortHeight
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// the details of the following structures don't matter to you, but they must
+// be visible so you can handle the memory allocations for them
+
+struct stbrp_node
+{
+ stbrp_coord x,y;
+ stbrp_node *next;
+};
+
+struct stbrp_context
+{
+ int width;
+ int height;
+ int align;
+ int init_mode;
+ int heuristic;
+ int num_nodes;
+ stbrp_node *active_head;
+ stbrp_node *free_head;
+ stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// IMPLEMENTATION SECTION
+//
+
+#ifdef STB_RECT_PACK_IMPLEMENTATION
+#ifndef STBRP_SORT
+#include <stdlib.h>
+#define STBRP_SORT qsort
+#endif
+
+#ifndef STBRP_ASSERT
+#include <assert.h>
+#define STBRP_ASSERT assert
+#endif
+
+#ifdef _MSC_VER
+#define STBRP__NOTUSED(v) (void)(v)
+#else
+#define STBRP__NOTUSED(v) (void)sizeof(v)
+#endif
+
+enum
+{
+ STBRP__INIT_skyline = 1
+};
+
+STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
+{
+ switch (context->init_mode) {
+ case STBRP__INIT_skyline:
+ STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
+ context->heuristic = heuristic;
+ break;
+ default:
+ STBRP_ASSERT(0);
+ }
+}
+
+STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
+{
+ if (allow_out_of_mem)
+ // if it's ok to run out of memory, then don't bother aligning them;
+ // this gives better packing, but may fail due to OOM (even though
+ // the rectangles easily fit). @TODO a smarter approach would be to only
+ // quantize once we've hit OOM, then we could get rid of this parameter.
+ context->align = 1;
+ else {
+ // if it's not ok to run out of memory, then quantize the widths
+ // so that num_nodes is always enough nodes.
+ //
+ // I.e. num_nodes * align >= width
+ // align >= width / num_nodes
+ // align = ceil(width/num_nodes)
+
+ context->align = (context->width + context->num_nodes-1) / context->num_nodes;
+ }
+}
+
+STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
+{
+ int i;
+#ifndef STBRP_LARGE_RECTS
+ STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
+#endif
+
+ for (i=0; i < num_nodes-1; ++i)
+ nodes[i].next = &nodes[i+1];
+ nodes[i].next = NULL;
+ context->init_mode = STBRP__INIT_skyline;
+ context->heuristic = STBRP_HEURISTIC_Skyline_default;
+ context->free_head = &nodes[0];
+ context->active_head = &context->extra[0];
+ context->width = width;
+ context->height = height;
+ context->num_nodes = num_nodes;
+ stbrp_setup_allow_out_of_mem(context, 0);
+
+ // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
+ context->extra[0].x = 0;
+ context->extra[0].y = 0;
+ context->extra[0].next = &context->extra[1];
+ context->extra[1].x = (stbrp_coord) width;
+#ifdef STBRP_LARGE_RECTS
+ context->extra[1].y = (1<<30);
+#else
+ context->extra[1].y = 65535;
+#endif
+ context->extra[1].next = NULL;
+}
+
+// find minimum y position if it starts at x1
+static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
+{
+ stbrp_node *node = first;
+ int x1 = x0 + width;
+ int min_y, visited_width, waste_area;
+
+ STBRP__NOTUSED(c);
+
+ STBRP_ASSERT(first->x <= x0);
+
+ #if 0
+ // skip in case we're past the node
+ while (node->next->x <= x0)
+ ++node;
+ #else
+ STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
+ #endif
+
+ STBRP_ASSERT(node->x <= x0);
+
+ min_y = 0;
+ waste_area = 0;
+ visited_width = 0;
+ while (node->x < x1) {
+ if (node->y > min_y) {
+ // raise min_y higher.
+ // we've accounted for all waste up to min_y,
+ // but we'll now add more waste for everything we've visted
+ waste_area += visited_width * (node->y - min_y);
+ min_y = node->y;
+ // the first time through, visited_width might be reduced
+ if (node->x < x0)
+ visited_width += node->next->x - x0;
+ else
+ visited_width += node->next->x - node->x;
+ } else {
+ // add waste area
+ int under_width = node->next->x - node->x;
+ if (under_width + visited_width > width)
+ under_width = width - visited_width;
+ waste_area += under_width * (min_y - node->y);
+ visited_width += under_width;
+ }
+ node = node->next;
+ }
+
+ *pwaste = waste_area;
+ return min_y;
+}
+
+typedef struct
+{
+ int x,y;
+ stbrp_node **prev_link;
+} stbrp__findresult;
+
+static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
+{
+ int best_waste = (1<<30), best_x, best_y = (1 << 30);
+ stbrp__findresult fr;
+ stbrp_node **prev, *node, *tail, **best = NULL;
+
+ // align to multiple of c->align
+ width = (width + c->align - 1);
+ width -= width % c->align;
+ STBRP_ASSERT(width % c->align == 0);
+
+ node = c->active_head;
+ prev = &c->active_head;
+ while (node->x + width <= c->width) {
+ int y,waste;
+ y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
+ if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
+ // bottom left
+ if (y < best_y) {
+ best_y = y;
+ best = prev;
+ }
+ } else {
+ // best-fit
+ if (y + height <= c->height) {
+ // can only use it if it first vertically
+ if (y < best_y || (y == best_y && waste < best_waste)) {
+ best_y = y;
+ best_waste = waste;
+ best = prev;
+ }
+ }
+ }
+ prev = &node->next;
+ node = node->next;
+ }
+
+ best_x = (best == NULL) ? 0 : (*best)->x;
+
+ // if doing best-fit (BF), we also have to try aligning right edge to each node position
+ //
+ // e.g, if fitting
+ //
+ // ____________________
+ // |____________________|
+ //
+ // into
+ //
+ // | |
+ // | ____________|
+ // |____________|
+ //
+ // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
+ //
+ // This makes BF take about 2x the time
+
+ if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
+ tail = c->active_head;
+ node = c->active_head;
+ prev = &c->active_head;
+ // find first node that's admissible
+ while (tail->x < width)
+ tail = tail->next;
+ while (tail) {
+ int xpos = tail->x - width;
+ int y,waste;
+ STBRP_ASSERT(xpos >= 0);
+ // find the left position that matches this
+ while (node->next->x <= xpos) {
+ prev = &node->next;
+ node = node->next;
+ }
+ STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
+ y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
+ if (y + height < c->height) {
+ if (y <= best_y) {
+ if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
+ best_x = xpos;
+ STBRP_ASSERT(y <= best_y);
+ best_y = y;
+ best_waste = waste;
+ best = prev;
+ }
+ }
+ }
+ tail = tail->next;
+ }
+ }
+
+ fr.prev_link = best;
+ fr.x = best_x;
+ fr.y = best_y;
+ return fr;
+}
+
+static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
+{
+ // find best position according to heuristic
+ stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
+ stbrp_node *node, *cur;
+
+ // bail if:
+ // 1. it failed
+ // 2. the best node doesn't fit (we don't always check this)
+ // 3. we're out of memory
+ if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
+ res.prev_link = NULL;
+ return res;
+ }
+
+ // on success, create new node
+ node = context->free_head;
+ node->x = (stbrp_coord) res.x;
+ node->y = (stbrp_coord) (res.y + height);
+
+ context->free_head = node->next;
+
+ // insert the new node into the right starting point, and
+ // let 'cur' point to the remaining nodes needing to be
+ // stiched back in
+
+ cur = *res.prev_link;
+ if (cur->x < res.x) {
+ // preserve the existing one, so start testing with the next one
+ stbrp_node *next = cur->next;
+ cur->next = node;
+ cur = next;
+ } else {
+ *res.prev_link = node;
+ }
+
+ // from here, traverse cur and free the nodes, until we get to one
+ // that shouldn't be freed
+ while (cur->next && cur->next->x <= res.x + width) {
+ stbrp_node *next = cur->next;
+ // move the current node to the free list
+ cur->next = context->free_head;
+ context->free_head = cur;
+ cur = next;
+ }
+
+ // stitch the list back in
+ node->next = cur;
+
+ if (cur->x < res.x + width)
+ cur->x = (stbrp_coord) (res.x + width);
+
+#ifdef _DEBUG
+ cur = context->active_head;
+ while (cur->x < context->width) {
+ STBRP_ASSERT(cur->x < cur->next->x);
+ cur = cur->next;
+ }
+ STBRP_ASSERT(cur->next == NULL);
+
+ {
+ stbrp_node *L1 = NULL, *L2 = NULL;
+ int count=0;
+ cur = context->active_head;
+ while (cur) {
+ L1 = cur;
+ cur = cur->next;
+ ++count;
+ }
+ cur = context->free_head;
+ while (cur) {
+ L2 = cur;
+ cur = cur->next;
+ ++count;
+ }
+ STBRP_ASSERT(count == context->num_nodes+2);
+ }
+#endif
+
+ return res;
+}
+
+static int rect_height_compare(const void *a, const void *b)
+{
+ const stbrp_rect *p = (const stbrp_rect *) a;
+ const stbrp_rect *q = (const stbrp_rect *) b;
+ if (p->h > q->h)
+ return -1;
+ if (p->h < q->h)
+ return 1;
+ return (p->w > q->w) ? -1 : (p->w < q->w);
+}
+
+static int rect_width_compare(const void *a, const void *b)
+{
+ const stbrp_rect *p = (const stbrp_rect *) a;
+ const stbrp_rect *q = (const stbrp_rect *) b;
+ if (p->w > q->w)
+ return -1;
+ if (p->w < q->w)
+ return 1;
+ return (p->h > q->h) ? -1 : (p->h < q->h);
+}
+
+static int rect_original_order(const void *a, const void *b)
+{
+ const stbrp_rect *p = (const stbrp_rect *) a;
+ const stbrp_rect *q = (const stbrp_rect *) b;
+ return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
+}
+
+#ifdef STBRP_LARGE_RECTS
+#define STBRP__MAXVAL 0xffffffff
+#else
+#define STBRP__MAXVAL 0xffff
+#endif
+
+STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
+{
+ int i;
+
+ // we use the 'was_packed' field internally to allow sorting/unsorting
+ for (i=0; i < num_rects; ++i) {
+ rects[i].was_packed = i;
+ #ifndef STBRP_LARGE_RECTS
+ STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);
+ #endif
+ }
+
+ // sort according to heuristic
+ STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
+
+ for (i=0; i < num_rects; ++i) {
+ if (rects[i].w == 0 || rects[i].h == 0) {
+ rects[i].x = rects[i].y = 0; // empty rect needs no space
+ } else {
+ stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
+ if (fr.prev_link) {
+ rects[i].x = (stbrp_coord) fr.x;
+ rects[i].y = (stbrp_coord) fr.y;
+ } else {
+ rects[i].x = rects[i].y = STBRP__MAXVAL;
+ }
+ }
+ }
+
+ // unsort
+ STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
+
+ // set was_packed flags
+ for (i=0; i < num_rects; ++i)
+ rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
+}
+#endif
diff --git a/src/external/stb_truetype.h b/src/external/stb_truetype.h
new file mode 100644
index 00000000..92b9a875
--- /dev/null
+++ b/src/external/stb_truetype.h
@@ -0,0 +1,4018 @@
+// stb_truetype.h - v1.14 - public domain
+// authored from 2009-2016 by Sean Barrett / RAD Game Tools
+//
+// This library processes TrueType files:
+// parse files
+// extract glyph metrics
+// extract glyph shapes
+// render glyphs to one-channel bitmaps with antialiasing (box filter)
+//
+// Todo:
+// non-MS cmaps
+// crashproof on bad data
+// hinting? (no longer patented)
+// cleartype-style AA?
+// optimize: use simple memory allocator for intermediates
+// optimize: build edge-list directly from curves
+// optimize: rasterize directly from curves?
+//
+// ADDITIONAL CONTRIBUTORS
+//
+// Mikko Mononen: compound shape support, more cmap formats
+// Tor Andersson: kerning, subpixel rendering
+// Dougall Johnson: OpenType / Type 2 font handling
+//
+// Misc other:
+// Ryan Gordon
+// Simon Glass
+// github:IntellectualKitty
+//
+// Bug/warning reports/fixes:
+// "Zer" on mollyrocket (with fix)
+// Cass Everitt
+// stoiko (Haemimont Games)
+// Brian Hook
+// Walter van Niftrik
+// David Gow
+// David Given
+// Ivan-Assen Ivanov
+// Anthony Pesch
+// Johan Duparc
+// Hou Qiming
+// Fabian "ryg" Giesen
+// Martins Mozeiko
+// Cap Petschulat
+// Omar Cornut
+// github:aloucks
+// Peter LaValle
+// Sergey Popov
+// Giumo X. Clanjor
+// Higor Euripedes
+// Thomas Fields
+// Derek Vinyard
+//
+// VERSION HISTORY
+//
+// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts, num-fonts-in-TTC function
+// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
+// 1.11 (2016-04-02) fix unused-variable warning
+// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef
+// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly
+// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
+// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
+// variant PackFontRanges to pack and render in separate phases;
+// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
+// fixed an assert() bug in the new rasterizer
+// replace assert() with STBTT_assert() in new rasterizer
+//
+// Full history can be found at the end of this file.
+//
+// LICENSE
+//
+// This software is dual-licensed to the public domain and under the following
+// license: you are granted a perpetual, irrevocable license to copy, modify,
+// publish, and distribute this file as you see fit.
+//
+// USAGE
+//
+// Include this file in whatever places neeed to refer to it. In ONE C/C++
+// file, write:
+// #define STB_TRUETYPE_IMPLEMENTATION
+// before the #include of this file. This expands out the actual
+// implementation into that C/C++ file.
+//
+// To make the implementation private to the file that generates the implementation,
+// #define STBTT_STATIC
+//
+// Simple 3D API (don't ship this, but it's fine for tools and quick start)
+// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture
+// stbtt_GetBakedQuad() -- compute quad to draw for a given char
+//
+// Improved 3D API (more shippable):
+// #include "stb_rect_pack.h" -- optional, but you really want it
+// stbtt_PackBegin()
+// stbtt_PackSetOversample() -- for improved quality on small fonts
+// stbtt_PackFontRanges() -- pack and renders
+// stbtt_PackEnd()
+// stbtt_GetPackedQuad()
+//
+// "Load" a font file from a memory buffer (you have to keep the buffer loaded)
+// stbtt_InitFont()
+// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections
+// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections
+//
+// Render a unicode codepoint to a bitmap
+// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap
+// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
+// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be
+//
+// Character advance/positioning
+// stbtt_GetCodepointHMetrics()
+// stbtt_GetFontVMetrics()
+// stbtt_GetCodepointKernAdvance()
+//
+// Starting with version 1.06, the rasterizer was replaced with a new,
+// faster and generally-more-precise rasterizer. The new rasterizer more
+// accurately measures pixel coverage for anti-aliasing, except in the case
+// where multiple shapes overlap, in which case it overestimates the AA pixel
+// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If
+// this turns out to be a problem, you can re-enable the old rasterizer with
+// #define STBTT_RASTERIZER_VERSION 1
+// which will incur about a 15% speed hit.
+//
+// ADDITIONAL DOCUMENTATION
+//
+// Immediately after this block comment are a series of sample programs.
+//
+// After the sample programs is the "header file" section. This section
+// includes documentation for each API function.
+//
+// Some important concepts to understand to use this library:
+//
+// Codepoint
+// Characters are defined by unicode codepoints, e.g. 65 is
+// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is
+// the hiragana for "ma".
+//
+// Glyph
+// A visual character shape (every codepoint is rendered as
+// some glyph)
+//
+// Glyph index
+// A font-specific integer ID representing a glyph
+//
+// Baseline
+// Glyph shapes are defined relative to a baseline, which is the
+// bottom of uppercase characters. Characters extend both above
+// and below the baseline.
+//
+// Current Point
+// As you draw text to the screen, you keep track of a "current point"
+// which is the origin of each character. The current point's vertical
+// position is the baseline. Even "baked fonts" use this model.
+//
+// Vertical Font Metrics
+// The vertical qualities of the font, used to vertically position
+// and space the characters. See docs for stbtt_GetFontVMetrics.
+//
+// Font Size in Pixels or Points
+// The preferred interface for specifying font sizes in stb_truetype
+// is to specify how tall the font's vertical extent should be in pixels.
+// If that sounds good enough, skip the next paragraph.
+//
+// Most font APIs instead use "points", which are a common typographic
+// measurement for describing font size, defined as 72 points per inch.
+// stb_truetype provides a point API for compatibility. However, true
+// "per inch" conventions don't make much sense on computer displays
+// since they different monitors have different number of pixels per
+// inch. For example, Windows traditionally uses a convention that
+// there are 96 pixels per inch, thus making 'inch' measurements have
+// nothing to do with inches, and thus effectively defining a point to
+// be 1.333 pixels. Additionally, the TrueType font data provides
+// an explicit scale factor to scale a given font's glyphs to points,
+// but the author has observed that this scale factor is often wrong
+// for non-commercial fonts, thus making fonts scaled in points
+// according to the TrueType spec incoherently sized in practice.
+//
+// ADVANCED USAGE
+//
+// Quality:
+//
+// - Use the functions with Subpixel at the end to allow your characters
+// to have subpixel positioning. Since the font is anti-aliased, not
+// hinted, this is very import for quality. (This is not possible with
+// baked fonts.)
+//
+// - Kerning is now supported, and if you're supporting subpixel rendering
+// then kerning is worth using to give your text a polished look.
+//
+// Performance:
+//
+// - Convert Unicode codepoints to glyph indexes and operate on the glyphs;
+// if you don't do this, stb_truetype is forced to do the conversion on
+// every call.
+//
+// - There are a lot of memory allocations. We should modify it to take
+// a temp buffer and allocate from the temp buffer (without freeing),
+// should help performance a lot.
+//
+// NOTES
+//
+// The system uses the raw data found in the .ttf file without changing it
+// and without building auxiliary data structures. This is a bit inefficient
+// on little-endian systems (the data is big-endian), but assuming you're
+// caching the bitmaps or glyph shapes this shouldn't be a big deal.
+//
+// It appears to be very hard to programmatically determine what font a
+// given file is in a general way. I provide an API for this, but I don't
+// recommend it.
+//
+//
+// SOURCE STATISTICS (based on v0.6c, 2050 LOC)
+//
+// Documentation & header file 520 LOC \___ 660 LOC documentation
+// Sample code 140 LOC /
+// Truetype parsing 620 LOC ---- 620 LOC TrueType
+// Software rasterization 240 LOC \ .
+// Curve tesselation 120 LOC \__ 550 LOC Bitmap creation
+// Bitmap management 100 LOC /
+// Baked bitmap interface 70 LOC /
+// Font name matching & access 150 LOC ---- 150
+// C runtime library abstraction 60 LOC ---- 60
+//
+//
+// PERFORMANCE MEASUREMENTS FOR 1.06:
+//
+// 32-bit 64-bit
+// Previous release: 8.83 s 7.68 s
+// Pool allocations: 7.72 s 6.34 s
+// Inline sort : 6.54 s 5.65 s
+// New rasterizer : 5.63 s 5.00 s
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+////
+//// SAMPLE PROGRAMS
+////
+//
+// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless
+//
+#if 0
+#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
+#include "stb_truetype.h"
+
+unsigned char ttf_buffer[1<<20];
+unsigned char temp_bitmap[512*512];
+
+stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs
+GLuint ftex;
+
+void my_stbtt_initfont(void)
+{
+ fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));
+ stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!
+ // can free ttf_buffer at this point
+ glGenTextures(1, &ftex);
+ glBindTexture(GL_TEXTURE_2D, ftex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);
+ // can free temp_bitmap at this point
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+}
+
+void my_stbtt_print(float x, float y, char *text)
+{
+ // assume orthographic projection with units = screen pixels, origin at top left
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, ftex);
+ glBegin(GL_QUADS);
+ while (*text) {
+ if (*text >= 32 && *text < 128) {
+ stbtt_aligned_quad q;
+ stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
+ glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);
+ glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);
+ glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);
+ glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);
+ }
+ ++text;
+ }
+ glEnd();
+}
+#endif
+//
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// Complete program (this compiles): get a single bitmap, print as ASCII art
+//
+#if 0
+#include <stdio.h>
+#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
+#include "stb_truetype.h"
+
+char ttf_buffer[1<<25];
+
+int main(int argc, char **argv)
+{
+ stbtt_fontinfo font;
+ unsigned char *bitmap;
+ int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);
+
+ fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));
+
+ stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));
+ bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);
+
+ for (j=0; j < h; ++j) {
+ for (i=0; i < w; ++i)
+ putchar(" .:ioVM@"[bitmap[j*w+i]>>5]);
+ putchar('\n');
+ }
+ return 0;
+}
+#endif
+//
+// Output:
+//
+// .ii.
+// @@@@@@.
+// V@Mio@@o
+// :i. V@V
+// :oM@@M
+// :@@@MM@M
+// @@o o@M
+// :@@. M@M
+// @@@o@@@@
+// :M@@V:@@.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// Complete program: print "Hello World!" banner, with bugs
+//
+#if 0
+char buffer[24<<20];
+unsigned char screen[20][79];
+
+int main(int arg, char **argv)
+{
+ stbtt_fontinfo font;
+ int i,j,ascent,baseline,ch=0;
+ float scale, xpos=2; // leave a little padding in case the character extends left
+ char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness
+
+ fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
+ stbtt_InitFont(&font, buffer, 0);
+
+ scale = stbtt_ScaleForPixelHeight(&font, 15);
+ stbtt_GetFontVMetrics(&font, &ascent,0,0);
+ baseline = (int) (ascent*scale);
+
+ while (text[ch]) {
+ int advance,lsb,x0,y0,x1,y1;
+ float x_shift = xpos - (float) floor(xpos);
+ stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);
+ stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);
+ stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);
+ // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong
+ // because this API is really for baking character bitmaps into textures. if you want to render
+ // a sequence of characters, you really need to render each bitmap to a temp buffer, then
+ // "alpha blend" that into the working buffer
+ xpos += (advance * scale);
+ if (text[ch+1])
+ xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);
+ ++ch;
+ }
+
+ for (j=0; j < 20; ++j) {
+ for (i=0; i < 78; ++i)
+ putchar(" .:ioVM@"[screen[j][i]>>5]);
+ putchar('\n');
+ }
+
+ return 0;
+}
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+////
+//// INTEGRATION WITH YOUR CODEBASE
+////
+//// The following sections allow you to supply alternate definitions
+//// of C library functions used by stb_truetype.
+
+#ifdef STB_TRUETYPE_IMPLEMENTATION
+ // #define your own (u)stbtt_int8/16/32 before including to override this
+ #ifndef stbtt_uint8
+ typedef unsigned char stbtt_uint8;
+ typedef signed char stbtt_int8;
+ typedef unsigned short stbtt_uint16;
+ typedef signed short stbtt_int16;
+ typedef unsigned int stbtt_uint32;
+ typedef signed int stbtt_int32;
+ #endif
+
+ typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];
+ typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];
+
+ // #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h
+ #ifndef STBTT_ifloor
+ #include <math.h>
+ #define STBTT_ifloor(x) ((int) floor(x))
+ #define STBTT_iceil(x) ((int) ceil(x))
+ #endif
+
+ #ifndef STBTT_sqrt
+ #include <math.h>
+ #define STBTT_sqrt(x) sqrt(x)
+ #endif
+
+ #ifndef STBTT_fabs
+ #include <math.h>
+ #define STBTT_fabs(x) fabs(x)
+ #endif
+
+ // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
+ #ifndef STBTT_malloc
+ #include <stdlib.h>
+ #define STBTT_malloc(x,u) ((void)(u),malloc(x))
+ #define STBTT_free(x,u) ((void)(u),free(x))
+ #endif
+
+ #ifndef STBTT_assert
+ #include <assert.h>
+ #define STBTT_assert(x) assert(x)
+ #endif
+
+ #ifndef STBTT_strlen
+ #include <string.h>
+ #define STBTT_strlen(x) strlen(x)
+ #endif
+
+ #ifndef STBTT_memcpy
+ #include <memory.h>
+ #define STBTT_memcpy memcpy
+ #define STBTT_memset memset
+ #endif
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+////
+//// INTERFACE
+////
+////
+
+#ifndef __STB_INCLUDE_STB_TRUETYPE_H__
+#define __STB_INCLUDE_STB_TRUETYPE_H__
+
+#ifdef STBTT_STATIC
+#define STBTT_DEF static
+#else
+#define STBTT_DEF extern
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// private structure
+typedef struct
+{
+ unsigned char *data;
+ int cursor;
+ int size;
+} stbtt__buf;
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// TEXTURE BAKING API
+//
+// If you use this API, you only have to call two functions ever.
+//
+
+typedef struct
+{
+ unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap
+ float xoff,yoff,xadvance;
+} stbtt_bakedchar;
+
+STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf)
+ float pixel_height, // height of font in pixels
+ unsigned char *pixels, int pw, int ph, // bitmap to be filled in
+ int first_char, int num_chars, // characters to bake
+ stbtt_bakedchar *chardata); // you allocate this, it's num_chars long
+// if return is positive, the first unused row of the bitmap
+// if return is negative, returns the negative of the number of characters that fit
+// if return is 0, no characters fit and no rows were used
+// This uses a very crappy packing.
+
+typedef struct
+{
+ float x0,y0,s0,t0; // top-left
+ float x1,y1,s1,t1; // bottom-right
+} stbtt_aligned_quad;
+
+STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, // same data as above
+ int char_index, // character to display
+ float *xpos, float *ypos, // pointers to current position in screen pixel space
+ stbtt_aligned_quad *q, // output: quad to draw
+ int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier
+// Call GetBakedQuad with char_index = 'character - first_char', and it
+// creates the quad you need to draw and advances the current position.
+//
+// The coordinate system used assumes y increases downwards.
+//
+// Characters will extend both above and below the current position;
+// see discussion of "BASELINE" above.
+//
+// It's inefficient; you might want to c&p it and optimize it.
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// NEW TEXTURE BAKING API
+//
+// This provides options for packing multiple fonts into one atlas, not
+// perfectly but better than nothing.
+
+typedef struct
+{
+ unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap
+ float xoff,yoff,xadvance;
+ float xoff2,yoff2;
+} stbtt_packedchar;
+
+typedef struct stbtt_pack_context stbtt_pack_context;
+typedef struct stbtt_fontinfo stbtt_fontinfo;
+#ifndef STB_RECT_PACK_VERSION
+typedef struct stbrp_rect stbrp_rect;
+#endif
+
+STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);
+// Initializes a packing context stored in the passed-in stbtt_pack_context.
+// Future calls using this context will pack characters into the bitmap passed
+// in here: a 1-channel bitmap that is width * height. stride_in_bytes is
+// the distance from one row to the next (or 0 to mean they are packed tightly
+// together). "padding" is the amount of padding to leave between each
+// character (normally you want '1' for bitmaps you'll use as textures with
+// bilinear filtering).
+//
+// Returns 0 on failure, 1 on success.
+
+STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc);
+// Cleans up the packing context and frees all memory.
+
+#define STBTT_POINT_SIZE(x) (-(x))
+
+STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size,
+ int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
+// Creates character bitmaps from the font_index'th font found in fontdata (use
+// font_index=0 if you don't know what that is). It creates num_chars_in_range
+// bitmaps for characters with unicode values starting at first_unicode_char_in_range
+// and increasing. Data for how to render them is stored in chardata_for_range;
+// pass these to stbtt_GetPackedQuad to get back renderable quads.
+//
+// font_size is the full height of the character from ascender to descender,
+// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed
+// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()
+// and pass that result as 'font_size':
+// ..., 20 , ... // font max minus min y is 20 pixels tall
+// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall
+
+typedef struct
+{
+ float font_size;
+ int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint
+ int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints
+ int num_chars;
+ stbtt_packedchar *chardata_for_range; // output
+ unsigned char h_oversample, v_oversample; // don't set these, they're used internally
+} stbtt_pack_range;
+
+STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
+// Creates character bitmaps from multiple ranges of characters stored in
+// ranges. This will usually create a better-packed bitmap than multiple
+// calls to stbtt_PackFontRange. Note that you can call this multiple
+// times within a single PackBegin/PackEnd.
+
+STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);
+// Oversampling a font increases the quality by allowing higher-quality subpixel
+// positioning, and is especially valuable at smaller text sizes.
+//
+// This function sets the amount of oversampling for all following calls to
+// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given
+// pack context. The default (no oversampling) is achieved by h_oversample=1
+// and v_oversample=1. The total number of pixels required is
+// h_oversample*v_oversample larger than the default; for example, 2x2
+// oversampling requires 4x the storage of 1x1. For best results, render
+// oversampled textures with bilinear filtering. Look at the readme in
+// stb/tests/oversample for information about oversampled fonts
+//
+// To use with PackFontRangesGather etc., you must set it before calls
+// call to PackFontRangesGatherRects.
+
+STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, // same data as above
+ int char_index, // character to display
+ float *xpos, float *ypos, // pointers to current position in screen pixel space
+ stbtt_aligned_quad *q, // output: quad to draw
+ int align_to_integer);
+
+STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
+STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);
+STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
+// Calling these functions in sequence is roughly equivalent to calling
+// stbtt_PackFontRanges(). If you more control over the packing of multiple
+// fonts, or if you want to pack custom data into a font texture, take a look
+// at the source to of stbtt_PackFontRanges() and create a custom version
+// using these functions, e.g. call GatherRects multiple times,
+// building up a single array of rects, then call PackRects once,
+// then call RenderIntoRects repeatedly. This may result in a
+// better packing than calling PackFontRanges multiple times
+// (or it may not).
+
+// this is an opaque structure that you shouldn't mess with which holds
+// all the context needed from PackBegin to PackEnd.
+struct stbtt_pack_context {
+ void *user_allocator_context;
+ void *pack_info;
+ int width;
+ int height;
+ int stride_in_bytes;
+ int padding;
+ unsigned int h_oversample, v_oversample;
+ unsigned char *pixels;
+ void *nodes;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// FONT LOADING
+//
+//
+
+STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);
+// This function will determine the number of fonts in a font file. TrueType
+// collection (.ttc) files may contain multiple fonts, while TrueType font
+// (.ttf) files only contain one font. The number of fonts can be used for
+// indexing with the previous function where the index is between zero and one
+// less than the total fonts. If an error occurs, -1 is returned.
+
+STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
+// Each .ttf/.ttc file may have more than one font. Each font has a sequential
+// index number starting from 0. Call this function to get the font offset for
+// a given index; it returns -1 if the index is out of range. A regular .ttf
+// file will only define one font and it always be at offset 0, so it will
+// return '0' for index 0, and -1 for all other indices.
+
+// The following structure is defined publically so you can declare one on
+// the stack or as a global or etc, but you should treat it as opaque.
+struct stbtt_fontinfo
+{
+ void * userdata;
+ unsigned char * data; // pointer to .ttf file
+ int fontstart; // offset of start of font
+
+ int numGlyphs; // number of glyphs, needed for range checking
+
+ int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf
+ int index_map; // a cmap mapping for our chosen character encoding
+ int indexToLocFormat; // format needed to map from glyph index to glyph
+
+ stbtt__buf cff; // cff font data
+ stbtt__buf charstrings; // the charstring index
+ stbtt__buf gsubrs; // global charstring subroutines index
+ stbtt__buf subrs; // private charstring subroutines index
+ stbtt__buf fontdicts; // array of font dicts
+ stbtt__buf fdselect; // map from glyph to fontdict
+};
+
+STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
+// Given an offset into the file that defines a font, this function builds
+// the necessary cached info for the rest of the system. You must allocate
+// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
+// need to do anything special to free it, because the contents are pure
+// value data with no additional data structures. Returns 0 on failure.
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// CHARACTER TO GLYPH-INDEX CONVERSIOn
+
+STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);
+// If you're going to perform multiple operations on the same character
+// and you want a speed-up, call this function with the character you're
+// going to process, then use glyph-based functions instead of the
+// codepoint-based functions.
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// CHARACTER PROPERTIES
+//
+
+STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);
+// computes a scale factor to produce a font whose "height" is 'pixels' tall.
+// Height is measured as the distance from the highest ascender to the lowest
+// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics
+// and computing:
+// scale = pixels / (ascent - descent)
+// so if you prefer to measure height by the ascent only, use a similar calculation.
+
+STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);
+// computes a scale factor to produce a font whose EM size is mapped to
+// 'pixels' tall. This is probably what traditional APIs compute, but
+// I'm not positive.
+
+STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);
+// ascent is the coordinate above the baseline the font extends; descent
+// is the coordinate below the baseline the font extends (i.e. it is typically negative)
+// lineGap is the spacing between one row's descent and the next row's ascent...
+// so you should advance the vertical position by "*ascent - *descent + *lineGap"
+// these are expressed in unscaled coordinates, so you must multiply by
+// the scale factor for a given size
+
+STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
+// the bounding box around all possible characters
+
+STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);
+// leftSideBearing is the offset from the current horizontal position to the left edge of the character
+// advanceWidth is the offset from the current horizontal position to the next horizontal position
+// these are expressed in unscaled coordinates
+
+STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);
+// an additional amount to add to the 'advance' value between ch1 and ch2
+
+STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);
+// Gets the bounding box of the visible part of the glyph, in unscaled coordinates
+
+STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);
+STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);
+STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
+// as above, but takes one or more glyph indices for greater efficiency
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// GLYPH SHAPES (you probably don't need these, but they have to go before
+// the bitmaps for C declaration-order reasons)
+//
+
+#ifndef STBTT_vmove // you can predefine these to use different values (but why?)
+ enum {
+ STBTT_vmove=1,
+ STBTT_vline,
+ STBTT_vcurve,
+ STBTT_vcubic
+ };
+#endif
+
+#ifndef stbtt_vertex // you can predefine this to use different values
+ // (we share this with other code at RAD)
+ #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file
+ typedef struct
+ {
+ stbtt_vertex_type x,y,cx,cy,cx1,cy1;
+ unsigned char type,padding;
+ } stbtt_vertex;
+#endif
+
+STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);
+// returns non-zero if nothing is drawn for this glyph
+
+STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);
+STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);
+// returns # of vertices and fills *vertices with the pointer to them
+// these are expressed in "unscaled" coordinates
+//
+// The shape is a series of countours. Each one starts with
+// a STBTT_moveto, then consists of a series of mixed
+// STBTT_lineto and STBTT_curveto segments. A lineto
+// draws a line from previous endpoint to its x,y; a curveto
+// draws a quadratic bezier from previous endpoint to
+// its x,y, using cx,cy as the bezier control point.
+
+STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
+// frees the data allocated above
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// BITMAP RENDERING
+//
+
+STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);
+// frees the bitmap allocated below
+
+STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
+// allocates a large-enough single-channel 8bpp bitmap and renders the
+// specified character/glyph at the specified scale into it, with
+// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).
+// *width & *height are filled out with the width & height of the bitmap,
+// which is stored left-to-right, top-to-bottom.
+//
+// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
+
+STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
+// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
+// shift for the character
+
+STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);
+// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap
+// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap
+// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the
+// width and height and positioning info for it first.
+
+STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);
+// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
+// shift for the character
+
+STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
+// get the bbox of the bitmap centered around the glyph origin; so the
+// bitmap width is ix1-ix0, height is iy1-iy0, and location to place
+// the bitmap top left is (leftSideBearing*scale,iy0).
+// (Note that the bitmap uses y-increases-down, but the shape uses
+// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
+
+STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
+// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel
+// shift for the character
+
+// the following functions are equivalent to the above functions, but operate
+// on glyph indices instead of Unicode codepoints (for efficiency)
+STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);
+STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);
+STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
+STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);
+STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
+STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
+
+
+// @TODO: don't expose this structure
+typedef struct
+{
+ int w,h,stride;
+ unsigned char *pixels;
+} stbtt__bitmap;
+
+// rasterize a shape with quadratic beziers into a bitmap
+STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into
+ float flatness_in_pixels, // allowable error of curve in pixels
+ stbtt_vertex *vertices, // array of vertices defining shape
+ int num_verts, // number of vertices in above array
+ float scale_x, float scale_y, // scale applied to input vertices
+ float shift_x, float shift_y, // translation applied to input vertices
+ int x_off, int y_off, // another translation applied to input
+ int invert, // if non-zero, vertically flip shape
+ void *userdata); // context for to STBTT_MALLOC
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Finding the right font...
+//
+// You should really just solve this offline, keep your own tables
+// of what font is what, and don't try to get it out of the .ttf file.
+// That's because getting it out of the .ttf file is really hard, because
+// the names in the file can appear in many possible encodings, in many
+// possible languages, and e.g. if you need a case-insensitive comparison,
+// the details of that depend on the encoding & language in a complex way
+// (actually underspecified in truetype, but also gigantic).
+//
+// But you can use the provided functions in two possible ways:
+// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on
+// unicode-encoded names to try to find the font you want;
+// you can run this before calling stbtt_InitFont()
+//
+// stbtt_GetFontNameString() lets you get any of the various strings
+// from the file yourself and do your own comparisons on them.
+// You have to have called stbtt_InitFont() first.
+
+
+STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);
+// returns the offset (not index) of the font that matches, or -1 if none
+// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".
+// if you use any other flag, use a font name like "Arial"; this checks
+// the 'macStyle' header field; i don't know if fonts set this consistently
+#define STBTT_MACSTYLE_DONTCARE 0
+#define STBTT_MACSTYLE_BOLD 1
+#define STBTT_MACSTYLE_ITALIC 2
+#define STBTT_MACSTYLE_UNDERSCORE 4
+#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0
+
+STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);
+// returns 1/0 whether the first string interpreted as utf8 is identical to
+// the second string interpreted as big-endian utf16... useful for strings from next func
+
+STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);
+// returns the string (which may be big-endian double byte, e.g. for unicode)
+// and puts the length in bytes in *length.
+//
+// some of the values for the IDs are below; for more see the truetype spec:
+// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
+// http://www.microsoft.com/typography/otspec/name.htm
+
+enum { // platformID
+ STBTT_PLATFORM_ID_UNICODE =0,
+ STBTT_PLATFORM_ID_MAC =1,
+ STBTT_PLATFORM_ID_ISO =2,
+ STBTT_PLATFORM_ID_MICROSOFT =3
+};
+
+enum { // encodingID for STBTT_PLATFORM_ID_UNICODE
+ STBTT_UNICODE_EID_UNICODE_1_0 =0,
+ STBTT_UNICODE_EID_UNICODE_1_1 =1,
+ STBTT_UNICODE_EID_ISO_10646 =2,
+ STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,
+ STBTT_UNICODE_EID_UNICODE_2_0_FULL=4
+};
+
+enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT
+ STBTT_MS_EID_SYMBOL =0,
+ STBTT_MS_EID_UNICODE_BMP =1,
+ STBTT_MS_EID_SHIFTJIS =2,
+ STBTT_MS_EID_UNICODE_FULL =10
+};
+
+enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes
+ STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4,
+ STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5,
+ STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6,
+ STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7
+};
+
+enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...
+ // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs
+ STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410,
+ STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411,
+ STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412,
+ STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419,
+ STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409,
+ STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D
+};
+
+enum { // languageID for STBTT_PLATFORM_ID_MAC
+ STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11,
+ STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23,
+ STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32,
+ STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 ,
+ STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 ,
+ STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,
+ STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __STB_INCLUDE_STB_TRUETYPE_H__
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+////
+//// IMPLEMENTATION
+////
+////
+
+#ifdef STB_TRUETYPE_IMPLEMENTATION
+
+#ifndef STBTT_MAX_OVERSAMPLE
+#define STBTT_MAX_OVERSAMPLE 8
+#endif
+
+#if STBTT_MAX_OVERSAMPLE > 255
+#error "STBTT_MAX_OVERSAMPLE cannot be > 255"
+#endif
+
+typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];
+
+#ifndef STBTT_RASTERIZER_VERSION
+#define STBTT_RASTERIZER_VERSION 2
+#endif
+
+#ifdef _MSC_VER
+#define STBTT__NOTUSED(v) (void)(v)
+#else
+#define STBTT__NOTUSED(v) (void)sizeof(v)
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+//
+// stbtt__buf helpers to parse data from file
+//
+
+static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)
+{
+ if (b->cursor >= b->size)
+ return 0;
+ return b->data[b->cursor++];
+}
+
+static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)
+{
+ if (b->cursor >= b->size)
+ return 0;
+ return b->data[b->cursor];
+}
+
+static void stbtt__buf_seek(stbtt__buf *b, int o)
+{
+ STBTT_assert(!(o > b->size || o < 0));
+ b->cursor = (o > b->size || o < 0) ? b->size : o;
+}
+
+static void stbtt__buf_skip(stbtt__buf *b, int o)
+{
+ stbtt__buf_seek(b, b->cursor + o);
+}
+
+static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)
+{
+ stbtt_uint32 v = 0;
+ int i;
+ STBTT_assert(n >= 1 && n <= 4);
+ for (i = 0; i < n; i++)
+ v = (v << 8) | stbtt__buf_get8(b);
+ return v;
+}
+
+static stbtt__buf stbtt__new_buf(const void *p, size_t size)
+{
+ stbtt__buf r;
+ STBTT_assert(size < 0x40000000);
+ r.data = (stbtt_uint8*) p;
+ r.size = (int) size;
+ r.cursor = 0;
+ return r;
+}
+
+#define stbtt__buf_get16(b) stbtt__buf_get((b), 2)
+#define stbtt__buf_get32(b) stbtt__buf_get((b), 4)
+
+static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s)
+{
+ stbtt__buf r = stbtt__new_buf(NULL, 0);
+ if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r;
+ r.data = b->data + o;
+ r.size = s;
+ return r;
+}
+
+static stbtt__buf stbtt__cff_get_index(stbtt__buf *b)
+{
+ int count, start, offsize;
+ start = b->cursor;
+ count = stbtt__buf_get16(b);
+ if (count) {
+ offsize = stbtt__buf_get8(b);
+ STBTT_assert(offsize >= 1 && offsize <= 4);
+ stbtt__buf_skip(b, offsize * count);
+ stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);
+ }
+ return stbtt__buf_range(b, start, b->cursor - start);
+}
+
+static stbtt_uint32 stbtt__cff_int(stbtt__buf *b)
+{
+ int b0 = stbtt__buf_get8(b);
+ if (b0 >= 32 && b0 <= 246) return b0 - 139;
+ else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;
+ else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;
+ else if (b0 == 28) return stbtt__buf_get16(b);
+ else if (b0 == 29) return stbtt__buf_get32(b);
+ STBTT_assert(0);
+ return 0;
+}
+
+static void stbtt__cff_skip_operand(stbtt__buf *b) {
+ int v, b0 = stbtt__buf_peek8(b);
+ STBTT_assert(b0 >= 28);
+ if (b0 == 30) {
+ stbtt__buf_skip(b, 1);
+ while (b->cursor < b->size) {
+ v = stbtt__buf_get8(b);
+ if ((v & 0xF) == 0xF || (v >> 4) == 0xF)
+ break;
+ }
+ } else {
+ stbtt__cff_int(b);
+ }
+}
+
+static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)
+{
+ stbtt__buf_seek(b, 0);
+ while (b->cursor < b->size) {
+ int start = b->cursor, end, op;
+ while (stbtt__buf_peek8(b) >= 28)
+ stbtt__cff_skip_operand(b);
+ end = b->cursor;
+ op = stbtt__buf_get8(b);
+ if (op == 12) op = stbtt__buf_get8(b) | 0x100;
+ if (op == key) return stbtt__buf_range(b, start, end-start);
+ }
+ return stbtt__buf_range(b, 0, 0);
+}
+
+static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out)
+{
+ int i;
+ stbtt__buf operands = stbtt__dict_get(b, key);
+ for (i = 0; i < outcount && operands.cursor < operands.size; i++)
+ out[i] = stbtt__cff_int(&operands);
+}
+
+static int stbtt__cff_index_count(stbtt__buf *b)
+{
+ stbtt__buf_seek(b, 0);
+ return stbtt__buf_get16(b);
+}
+
+static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)
+{
+ int count, offsize, start, end;
+ stbtt__buf_seek(&b, 0);
+ count = stbtt__buf_get16(&b);
+ offsize = stbtt__buf_get8(&b);
+ STBTT_assert(i >= 0 && i < count);
+ STBTT_assert(offsize >= 1 && offsize <= 4);
+ stbtt__buf_skip(&b, i*offsize);
+ start = stbtt__buf_get(&b, offsize);
+ end = stbtt__buf_get(&b, offsize);
+ return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// accessors to parse data from file
+//
+
+// on platforms that don't allow misaligned reads, if we want to allow
+// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE
+
+#define ttBYTE(p) (* (stbtt_uint8 *) (p))
+#define ttCHAR(p) (* (stbtt_int8 *) (p))
+#define ttFixed(p) ttLONG(p)
+
+static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }
+static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }
+static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
+static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
+
+#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
+#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3])
+
+static int stbtt__isfont(stbtt_uint8 *font)
+{
+ // check the version number
+ if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1
+ if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this!
+ if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF
+ if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0
+ if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts
+ return 0;
+}
+
+// @OPTIMIZE: binary search
+static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)
+{
+ stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);
+ stbtt_uint32 tabledir = fontstart + 12;
+ stbtt_int32 i;
+ for (i=0; i < num_tables; ++i) {
+ stbtt_uint32 loc = tabledir + 16*i;
+ if (stbtt_tag(data+loc+0, tag))
+ return ttULONG(data+loc+8);
+ }
+ return 0;
+}
+
+static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index)
+{
+ // if it's just a font, there's only one valid index
+ if (stbtt__isfont(font_collection))
+ return index == 0 ? 0 : -1;
+
+ // check if it's a TTC
+ if (stbtt_tag(font_collection, "ttcf")) {
+ // version 1?
+ if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
+ stbtt_int32 n = ttLONG(font_collection+8);
+ if (index >= n)
+ return -1;
+ return ttULONG(font_collection+12+index*4);
+ }
+ }
+ return -1;
+}
+
+static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection)
+{
+ // if it's just a font, there's only one valid font
+ if (stbtt__isfont(font_collection))
+ return 1;
+
+ // check if it's a TTC
+ if (stbtt_tag(font_collection, "ttcf")) {
+ // version 1?
+ if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
+ return ttLONG(font_collection+8);
+ }
+ }
+ return 0;
+}
+
+static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
+{
+ stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 };
+ stbtt__buf pdict;
+ stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);
+ if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0);
+ pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);
+ stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);
+ if (!subrsoff) return stbtt__new_buf(NULL, 0);
+ stbtt__buf_seek(&cff, private_loc[1]+subrsoff);
+ return stbtt__cff_get_index(&cff);
+}
+
+static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
+{
+ stbtt_uint32 cmap, t;
+ stbtt_int32 i,numTables;
+
+ info->data = data;
+ info->fontstart = fontstart;
+ info->cff = stbtt__new_buf(NULL, 0);
+
+ cmap = stbtt__find_table(data, fontstart, "cmap"); // required
+ info->loca = stbtt__find_table(data, fontstart, "loca"); // required
+ info->head = stbtt__find_table(data, fontstart, "head"); // required
+ info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required
+ info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required
+ info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
+ info->kern = stbtt__find_table(data, fontstart, "kern"); // not required
+
+ if (!cmap || !info->head || !info->hhea || !info->hmtx)
+ return 0;
+ if (info->glyf) {
+ // required for truetype
+ if (!info->loca) return 0;
+ } else {
+ // initialization for CFF / Type2 fonts (OTF)
+ stbtt__buf b, topdict, topdictidx;
+ stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;
+ stbtt_uint32 cff;
+
+ cff = stbtt__find_table(data, fontstart, "CFF ");
+ if (!cff) return 0;
+
+ info->fontdicts = stbtt__new_buf(NULL, 0);
+ info->fdselect = stbtt__new_buf(NULL, 0);
+
+ // @TODO this should use size from table (not 512MB)
+ info->cff = stbtt__new_buf(data+cff, 512*1024*1024);
+ b = info->cff;
+
+ // read the header
+ stbtt__buf_skip(&b, 2);
+ stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize
+
+ // @TODO the name INDEX could list multiple fonts,
+ // but we just use the first one.
+ stbtt__cff_get_index(&b); // name INDEX
+ topdictidx = stbtt__cff_get_index(&b);
+ topdict = stbtt__cff_index_get(topdictidx, 0);
+ stbtt__cff_get_index(&b); // string INDEX
+ info->gsubrs = stbtt__cff_get_index(&b);
+
+ stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);
+ stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);
+ stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);
+ stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);
+ info->subrs = stbtt__get_subrs(b, topdict);
+
+ // we only support Type 2 charstrings
+ if (cstype != 2) return 0;
+ if (charstrings == 0) return 0;
+
+ if (fdarrayoff) {
+ // looks like a CID font
+ if (!fdselectoff) return 0;
+ stbtt__buf_seek(&b, fdarrayoff);
+ info->fontdicts = stbtt__cff_get_index(&b);
+ info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);
+ }
+
+ stbtt__buf_seek(&b, charstrings);
+ info->charstrings = stbtt__cff_get_index(&b);
+ }
+
+ t = stbtt__find_table(data, fontstart, "maxp");
+ if (t)
+ info->numGlyphs = ttUSHORT(data+t+4);
+ else
+ info->numGlyphs = 0xffff;
+
+ // find a cmap encoding table we understand *now* to avoid searching
+ // later. (todo: could make this installable)
+ // the same regardless of glyph.
+ numTables = ttUSHORT(data + cmap + 2);
+ info->index_map = 0;
+ for (i=0; i < numTables; ++i) {
+ stbtt_uint32 encoding_record = cmap + 4 + 8 * i;
+ // find an encoding we understand:
+ switch(ttUSHORT(data+encoding_record)) {
+ case STBTT_PLATFORM_ID_MICROSOFT:
+ switch (ttUSHORT(data+encoding_record+2)) {
+ case STBTT_MS_EID_UNICODE_BMP:
+ case STBTT_MS_EID_UNICODE_FULL:
+ // MS/Unicode
+ info->index_map = cmap + ttULONG(data+encoding_record+4);
+ break;
+ }
+ break;
+ case STBTT_PLATFORM_ID_UNICODE:
+ // Mac/iOS has these
+ // all the encodingIDs are unicode, so we don't bother to check it
+ info->index_map = cmap + ttULONG(data+encoding_record+4);
+ break;
+ }
+ }
+ if (info->index_map == 0)
+ return 0;
+
+ info->indexToLocFormat = ttUSHORT(data+info->head + 50);
+ return 1;
+}
+
+STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)
+{
+ stbtt_uint8 *data = info->data;
+ stbtt_uint32 index_map = info->index_map;
+
+ stbtt_uint16 format = ttUSHORT(data + index_map + 0);
+ if (format == 0) { // apple byte encoding
+ stbtt_int32 bytes = ttUSHORT(data + index_map + 2);
+ if (unicode_codepoint < bytes-6)
+ return ttBYTE(data + index_map + 6 + unicode_codepoint);
+ return 0;
+ } else if (format == 6) {
+ stbtt_uint32 first = ttUSHORT(data + index_map + 6);
+ stbtt_uint32 count = ttUSHORT(data + index_map + 8);
+ if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)
+ return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);
+ return 0;
+ } else if (format == 2) {
+ STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean
+ return 0;
+ } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges
+ stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;
+ stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;
+ stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);
+ stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;
+
+ // do a binary search of the segments
+ stbtt_uint32 endCount = index_map + 14;
+ stbtt_uint32 search = endCount;
+
+ if (unicode_codepoint > 0xffff)
+ return 0;
+
+ // they lie from endCount .. endCount + segCount
+ // but searchRange is the nearest power of two, so...
+ if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))
+ search += rangeShift*2;
+
+ // now decrement to bias correctly to find smallest
+ search -= 2;
+ while (entrySelector) {
+ stbtt_uint16 end;
+ searchRange >>= 1;
+ end = ttUSHORT(data + search + searchRange*2);
+ if (unicode_codepoint > end)
+ search += searchRange*2;
+ --entrySelector;
+ }
+ search += 2;
+
+ {
+ stbtt_uint16 offset, start;
+ stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
+
+ STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
+ start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
+ if (unicode_codepoint < start)
+ return 0;
+
+ offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
+ if (offset == 0)
+ return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
+
+ return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
+ }
+ } else if (format == 12 || format == 13) {
+ stbtt_uint32 ngroups = ttULONG(data+index_map+12);
+ stbtt_int32 low,high;
+ low = 0; high = (stbtt_int32)ngroups;
+ // Binary search the right group.
+ while (low < high) {
+ stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high
+ stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);
+ stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);
+ if ((stbtt_uint32) unicode_codepoint < start_char)
+ high = mid;
+ else if ((stbtt_uint32) unicode_codepoint > end_char)
+ low = mid+1;
+ else {
+ stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);
+ if (format == 12)
+ return start_glyph + unicode_codepoint-start_char;
+ else // format == 13
+ return start_glyph;
+ }
+ }
+ return 0; // not found
+ }
+ // @TODO
+ STBTT_assert(0);
+ return 0;
+}
+
+STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)
+{
+ return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);
+}
+
+static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)
+{
+ v->type = type;
+ v->x = (stbtt_int16) x;
+ v->y = (stbtt_int16) y;
+ v->cx = (stbtt_int16) cx;
+ v->cy = (stbtt_int16) cy;
+}
+
+static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)
+{
+ int g1,g2;
+
+ STBTT_assert(!info->cff.size);
+
+ if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range
+ if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format
+
+ if (info->indexToLocFormat == 0) {
+ g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;
+ g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;
+ } else {
+ g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);
+ g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);
+ }
+
+ return g1==g2 ? -1 : g1; // if length is 0, return -1
+}
+
+static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
+
+STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
+{
+ if (info->cff.size) {
+ stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);
+ } else {
+ int g = stbtt__GetGlyfOffset(info, glyph_index);
+ if (g < 0) return 0;
+
+ if (x0) *x0 = ttSHORT(info->data + g + 2);
+ if (y0) *y0 = ttSHORT(info->data + g + 4);
+ if (x1) *x1 = ttSHORT(info->data + g + 6);
+ if (y1) *y1 = ttSHORT(info->data + g + 8);
+ }
+ return 1;
+}
+
+STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)
+{
+ return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);
+}
+
+STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)
+{
+ stbtt_int16 numberOfContours;
+ int g;
+ if (info->cff.size)
+ return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;
+ g = stbtt__GetGlyfOffset(info, glyph_index);
+ if (g < 0) return 1;
+ numberOfContours = ttSHORT(info->data + g);
+ return numberOfContours == 0;
+}
+
+static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,
+ stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)
+{
+ if (start_off) {
+ if (was_off)
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);
+ } else {
+ if (was_off)
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);
+ else
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);
+ }
+ return num_vertices;
+}
+
+static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
+{
+ stbtt_int16 numberOfContours;
+ stbtt_uint8 *endPtsOfContours;
+ stbtt_uint8 *data = info->data;
+ stbtt_vertex *vertices=0;
+ int num_vertices=0;
+ int g = stbtt__GetGlyfOffset(info, glyph_index);
+
+ *pvertices = NULL;
+
+ if (g < 0) return 0;
+
+ numberOfContours = ttSHORT(data + g);
+
+ if (numberOfContours > 0) {
+ stbtt_uint8 flags=0,flagcount;
+ stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
+ stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;
+ stbtt_uint8 *points;
+ endPtsOfContours = (data + g + 10);
+ ins = ttUSHORT(data + g + 10 + numberOfContours * 2);
+ points = data + g + 10 + numberOfContours * 2 + 2 + ins;
+
+ n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);
+
+ m = n + 2*numberOfContours; // a loose bound on how many vertices we might need
+ vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);
+ if (vertices == 0)
+ return 0;
+
+ next_move = 0;
+ flagcount=0;
+
+ // in first pass, we load uninterpreted data into the allocated array
+ // above, shifted to the end of the array so we won't overwrite it when
+ // we create our final data starting from the front
+
+ off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated
+
+ // first load flags
+
+ for (i=0; i < n; ++i) {
+ if (flagcount == 0) {
+ flags = *points++;
+ if (flags & 8)
+ flagcount = *points++;
+ } else
+ --flagcount;
+ vertices[off+i].type = flags;
+ }
+
+ // now load x coordinates
+ x=0;
+ for (i=0; i < n; ++i) {
+ flags = vertices[off+i].type;
+ if (flags & 2) {
+ stbtt_int16 dx = *points++;
+ x += (flags & 16) ? dx : -dx; // ???
+ } else {
+ if (!(flags & 16)) {
+ x = x + (stbtt_int16) (points[0]*256 + points[1]);
+ points += 2;
+ }
+ }
+ vertices[off+i].x = (stbtt_int16) x;
+ }
+
+ // now load y coordinates
+ y=0;
+ for (i=0; i < n; ++i) {
+ flags = vertices[off+i].type;
+ if (flags & 4) {
+ stbtt_int16 dy = *points++;
+ y += (flags & 32) ? dy : -dy; // ???
+ } else {
+ if (!(flags & 32)) {
+ y = y + (stbtt_int16) (points[0]*256 + points[1]);
+ points += 2;
+ }
+ }
+ vertices[off+i].y = (stbtt_int16) y;
+ }
+
+ // now convert them to our format
+ num_vertices=0;
+ sx = sy = cx = cy = scx = scy = 0;
+ for (i=0; i < n; ++i) {
+ flags = vertices[off+i].type;
+ x = (stbtt_int16) vertices[off+i].x;
+ y = (stbtt_int16) vertices[off+i].y;
+
+ if (next_move == i) {
+ if (i != 0)
+ num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
+
+ // now start the new one
+ start_off = !(flags & 1);
+ if (start_off) {
+ // if we start off with an off-curve point, then when we need to find a point on the curve
+ // where we can start, and we need to save some state for when we wraparound.
+ scx = x;
+ scy = y;
+ if (!(vertices[off+i+1].type & 1)) {
+ // next point is also a curve point, so interpolate an on-point curve
+ sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;
+ sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;
+ } else {
+ // otherwise just use the next point as our start point
+ sx = (stbtt_int32) vertices[off+i+1].x;
+ sy = (stbtt_int32) vertices[off+i+1].y;
+ ++i; // we're using point i+1 as the starting point, so skip it
+ }
+ } else {
+ sx = x;
+ sy = y;
+ }
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);
+ was_off = 0;
+ next_move = 1 + ttUSHORT(endPtsOfContours+j*2);
+ ++j;
+ } else {
+ if (!(flags & 1)) { // if it's a curve
+ if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);
+ cx = x;
+ cy = y;
+ was_off = 1;
+ } else {
+ if (was_off)
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);
+ else
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);
+ was_off = 0;
+ }
+ }
+ }
+ num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
+ } else if (numberOfContours == -1) {
+ // Compound shapes.
+ int more = 1;
+ stbtt_uint8 *comp = data + g + 10;
+ num_vertices = 0;
+ vertices = 0;
+ while (more) {
+ stbtt_uint16 flags, gidx;
+ int comp_num_verts = 0, i;
+ stbtt_vertex *comp_verts = 0, *tmp = 0;
+ float mtx[6] = {1,0,0,1,0,0}, m, n;
+
+ flags = ttSHORT(comp); comp+=2;
+ gidx = ttSHORT(comp); comp+=2;
+
+ if (flags & 2) { // XY values
+ if (flags & 1) { // shorts
+ mtx[4] = ttSHORT(comp); comp+=2;
+ mtx[5] = ttSHORT(comp); comp+=2;
+ } else {
+ mtx[4] = ttCHAR(comp); comp+=1;
+ mtx[5] = ttCHAR(comp); comp+=1;
+ }
+ }
+ else {
+ // @TODO handle matching point
+ STBTT_assert(0);
+ }
+ if (flags & (1<<3)) { // WE_HAVE_A_SCALE
+ mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
+ mtx[1] = mtx[2] = 0;
+ } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE
+ mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
+ mtx[1] = mtx[2] = 0;
+ mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
+ } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO
+ mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
+ mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;
+ mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
+ mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
+ }
+
+ // Find transformation scales.
+ m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
+ n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
+
+ // Get indexed glyph.
+ comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);
+ if (comp_num_verts > 0) {
+ // Transform vertices.
+ for (i = 0; i < comp_num_verts; ++i) {
+ stbtt_vertex* v = &comp_verts[i];
+ stbtt_vertex_type x,y;
+ x=v->x; y=v->y;
+ v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
+ v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
+ x=v->cx; y=v->cy;
+ v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
+ v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
+ }
+ // Append vertices.
+ tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);
+ if (!tmp) {
+ if (vertices) STBTT_free(vertices, info->userdata);
+ if (comp_verts) STBTT_free(comp_verts, info->userdata);
+ return 0;
+ }
+ if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
+ STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
+ if (vertices) STBTT_free(vertices, info->userdata);
+ vertices = tmp;
+ STBTT_free(comp_verts, info->userdata);
+ num_vertices += comp_num_verts;
+ }
+ // More components ?
+ more = flags & (1<<5);
+ }
+ } else if (numberOfContours < 0) {
+ // @TODO other compound variations?
+ STBTT_assert(0);
+ } else {
+ // numberOfCounters == 0, do nothing
+ }
+
+ *pvertices = vertices;
+ return num_vertices;
+}
+
+typedef struct
+{
+ int bounds;
+ int started;
+ float first_x, first_y;
+ float x, y;
+ stbtt_int32 min_x, max_x, min_y, max_y;
+
+ stbtt_vertex *pvertices;
+ int num_vertices;
+} stbtt__csctx;
+
+#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}
+
+static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)
+{
+ if (x > c->max_x || !c->started) c->max_x = x;
+ if (y > c->max_y || !c->started) c->max_y = y;
+ if (x < c->min_x || !c->started) c->min_x = x;
+ if (y < c->min_y || !c->started) c->min_y = y;
+ c->started = 1;
+}
+
+static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1)
+{
+ if (c->bounds) {
+ stbtt__track_vertex(c, x, y);
+ if (type == STBTT_vcubic) {
+ stbtt__track_vertex(c, cx, cy);
+ stbtt__track_vertex(c, cx1, cy1);
+ }
+ } else {
+ stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);
+ c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;
+ c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;
+ }
+ c->num_vertices++;
+}
+
+static void stbtt__csctx_close_shape(stbtt__csctx *ctx)
+{
+ if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)
+ stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);
+}
+
+static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)
+{
+ stbtt__csctx_close_shape(ctx);
+ ctx->first_x = ctx->x = ctx->x + dx;
+ ctx->first_y = ctx->y = ctx->y + dy;
+ stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
+}
+
+static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)
+{
+ ctx->x += dx;
+ ctx->y += dy;
+ stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
+}
+
+static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)
+{
+ float cx1 = ctx->x + dx1;
+ float cy1 = ctx->y + dy1;
+ float cx2 = cx1 + dx2;
+ float cy2 = cy1 + dy2;
+ ctx->x = cx2 + dx3;
+ ctx->y = cy2 + dy3;
+ stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);
+}
+
+static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)
+{
+ int count = stbtt__cff_index_count(&idx);
+ int bias = 107;
+ if (count >= 33900)
+ bias = 32768;
+ else if (count >= 1240)
+ bias = 1131;
+ n += bias;
+ if (n < 0 || n >= count)
+ return stbtt__new_buf(NULL, 0);
+ return stbtt__cff_index_get(idx, n);
+}
+
+static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index)
+{
+ stbtt__buf fdselect = info->fdselect;
+ int nranges, start, end, v, fmt, fdselector = -1, i;
+
+ stbtt__buf_seek(&fdselect, 0);
+ fmt = stbtt__buf_get8(&fdselect);
+ if (fmt == 0) {
+ // untested
+ stbtt__buf_skip(&fdselect, glyph_index);
+ fdselector = stbtt__buf_get8(&fdselect);
+ } else if (fmt == 3) {
+ nranges = stbtt__buf_get16(&fdselect);
+ start = stbtt__buf_get16(&fdselect);
+ for (i = 0; i < nranges; i++) {
+ v = stbtt__buf_get8(&fdselect);
+ end = stbtt__buf_get16(&fdselect);
+ if (glyph_index >= start && glyph_index < end) {
+ fdselector = v;
+ break;
+ }
+ start = end;
+ }
+ }
+ if (fdselector == -1) stbtt__new_buf(NULL, 0);
+ return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));
+}
+
+static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)
+{
+ int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;
+ int has_subrs = 0, clear_stack;
+ float s[48];
+ stbtt__buf subr_stack[10], subrs = info->subrs, b;
+ float f;
+
+#define STBTT__CSERR(s) (0)
+
+ // this currently ignores the initial width value, which isn't needed if we have hmtx
+ b = stbtt__cff_index_get(info->charstrings, glyph_index);
+ while (b.cursor < b.size) {
+ i = 0;
+ clear_stack = 1;
+ b0 = stbtt__buf_get8(&b);
+ switch (b0) {
+ // @TODO implement hinting
+ case 0x13: // hintmask
+ case 0x14: // cntrmask
+ if (in_header)
+ maskbits += (sp / 2); // implicit "vstem"
+ in_header = 0;
+ stbtt__buf_skip(&b, (maskbits + 7) / 8);
+ break;
+
+ case 0x01: // hstem
+ case 0x03: // vstem
+ case 0x12: // hstemhm
+ case 0x17: // vstemhm
+ maskbits += (sp / 2);
+ break;
+
+ case 0x15: // rmoveto
+ in_header = 0;
+ if (sp < 2) return STBTT__CSERR("rmoveto stack");
+ stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);
+ break;
+ case 0x04: // vmoveto
+ in_header = 0;
+ if (sp < 1) return STBTT__CSERR("vmoveto stack");
+ stbtt__csctx_rmove_to(c, 0, s[sp-1]);
+ break;
+ case 0x16: // hmoveto
+ in_header = 0;
+ if (sp < 1) return STBTT__CSERR("hmoveto stack");
+ stbtt__csctx_rmove_to(c, s[sp-1], 0);
+ break;
+
+ case 0x05: // rlineto
+ if (sp < 2) return STBTT__CSERR("rlineto stack");
+ for (; i + 1 < sp; i += 2)
+ stbtt__csctx_rline_to(c, s[i], s[i+1]);
+ break;
+
+ // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical
+ // starting from a different place.
+
+ case 0x07: // vlineto
+ if (sp < 1) return STBTT__CSERR("vlineto stack");
+ goto vlineto;
+ case 0x06: // hlineto
+ if (sp < 1) return STBTT__CSERR("hlineto stack");
+ for (;;) {
+ if (i >= sp) break;
+ stbtt__csctx_rline_to(c, s[i], 0);
+ i++;
+ vlineto:
+ if (i >= sp) break;
+ stbtt__csctx_rline_to(c, 0, s[i]);
+ i++;
+ }
+ break;
+
+ case 0x1F: // hvcurveto
+ if (sp < 4) return STBTT__CSERR("hvcurveto stack");
+ goto hvcurveto;
+ case 0x1E: // vhcurveto
+ if (sp < 4) return STBTT__CSERR("vhcurveto stack");
+ for (;;) {
+ if (i + 3 >= sp) break;
+ stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);
+ i += 4;
+ hvcurveto:
+ if (i + 3 >= sp) break;
+ stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);
+ i += 4;
+ }
+ break;
+
+ case 0x08: // rrcurveto
+ if (sp < 6) return STBTT__CSERR("rcurveline stack");
+ for (; i + 5 < sp; i += 6)
+ stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
+ break;
+
+ case 0x18: // rcurveline
+ if (sp < 8) return STBTT__CSERR("rcurveline stack");
+ for (; i + 5 < sp - 2; i += 6)
+ stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
+ if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");
+ stbtt__csctx_rline_to(c, s[i], s[i+1]);
+ break;
+
+ case 0x19: // rlinecurve
+ if (sp < 8) return STBTT__CSERR("rlinecurve stack");
+ for (; i + 1 < sp - 6; i += 2)
+ stbtt__csctx_rline_to(c, s[i], s[i+1]);
+ if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");
+ stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
+ break;
+
+ case 0x1A: // vvcurveto
+ case 0x1B: // hhcurveto
+ if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack");
+ f = 0.0;
+ if (sp & 1) { f = s[i]; i++; }
+ for (; i + 3 < sp; i += 4) {
+ if (b0 == 0x1B)
+ stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);
+ else
+ stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);
+ f = 0.0;
+ }
+ break;
+
+ case 0x0A: // callsubr
+ if (!has_subrs) {
+ if (info->fdselect.size)
+ subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
+ has_subrs = 1;
+ }
+ // fallthrough
+ case 0x1D: // callgsubr
+ if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
+ v = (int) s[--sp];
+ if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");
+ subr_stack[subr_stack_height++] = b;
+ b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);
+ if (b.size == 0) return STBTT__CSERR("subr not found");
+ b.cursor = 0;
+ clear_stack = 0;
+ break;
+
+ case 0x0B: // return
+ if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr");
+ b = subr_stack[--subr_stack_height];
+ clear_stack = 0;
+ break;
+
+ case 0x0E: // endchar
+ stbtt__csctx_close_shape(c);
+ return 1;
+
+ case 0x0C: { // two-byte escape
+ float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;
+ float dx, dy;
+ int b1 = stbtt__buf_get8(&b);
+ switch (b1) {
+ // @TODO These "flex" implementations ignore the flex-depth and resolution,
+ // and always draw beziers.
+ case 0x22: // hflex
+ if (sp < 7) return STBTT__CSERR("hflex stack");
+ dx1 = s[0];
+ dx2 = s[1];
+ dy2 = s[2];
+ dx3 = s[3];
+ dx4 = s[4];
+ dx5 = s[5];
+ dx6 = s[6];
+ stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);
+ stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);
+ break;
+
+ case 0x23: // flex
+ if (sp < 13) return STBTT__CSERR("flex stack");
+ dx1 = s[0];
+ dy1 = s[1];
+ dx2 = s[2];
+ dy2 = s[3];
+ dx3 = s[4];
+ dy3 = s[5];
+ dx4 = s[6];
+ dy4 = s[7];
+ dx5 = s[8];
+ dy5 = s[9];
+ dx6 = s[10];
+ dy6 = s[11];
+ //fd is s[12]
+ stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
+ stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
+ break;
+
+ case 0x24: // hflex1
+ if (sp < 9) return STBTT__CSERR("hflex1 stack");
+ dx1 = s[0];
+ dy1 = s[1];
+ dx2 = s[2];
+ dy2 = s[3];
+ dx3 = s[4];
+ dx4 = s[5];
+ dx5 = s[6];
+ dy5 = s[7];
+ dx6 = s[8];
+ stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);
+ stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));
+ break;
+
+ case 0x25: // flex1
+ if (sp < 11) return STBTT__CSERR("flex1 stack");
+ dx1 = s[0];
+ dy1 = s[1];
+ dx2 = s[2];
+ dy2 = s[3];
+ dx3 = s[4];
+ dy3 = s[5];
+ dx4 = s[6];
+ dy4 = s[7];
+ dx5 = s[8];
+ dy5 = s[9];
+ dx6 = dy6 = s[10];
+ dx = dx1+dx2+dx3+dx4+dx5;
+ dy = dy1+dy2+dy3+dy4+dy5;
+ if (STBTT_fabs(dx) > STBTT_fabs(dy))
+ dy6 = -dy;
+ else
+ dx6 = -dx;
+ stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
+ stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
+ break;
+
+ default:
+ return STBTT__CSERR("unimplemented");
+ }
+ } break;
+
+ default:
+ if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
+ return STBTT__CSERR("reserved operator");
+
+ // push immediate
+ if (b0 == 255) {
+ f = (float)stbtt__buf_get32(&b) / 0x10000;
+ } else {
+ stbtt__buf_skip(&b, -1);
+ f = (float)(stbtt_int16)stbtt__cff_int(&b);
+ }
+ if (sp >= 48) return STBTT__CSERR("push stack overflow");
+ s[sp++] = f;
+ clear_stack = 0;
+ break;
+ }
+ if (clear_stack) sp = 0;
+ }
+ return STBTT__CSERR("no endchar");
+
+#undef STBTT__CSERR
+}
+
+static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
+{
+ // runs the charstring twice, once to count and once to output (to avoid realloc)
+ stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1);
+ stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);
+ if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {
+ *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);
+ output_ctx.pvertices = *pvertices;
+ if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {
+ STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices);
+ return output_ctx.num_vertices;
+ }
+ }
+ *pvertices = NULL;
+ return 0;
+}
+
+static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
+{
+ stbtt__csctx c = STBTT__CSCTX_INIT(1);
+ int r = stbtt__run_charstring(info, glyph_index, &c);
+ if (x0) {
+ *x0 = r ? c.min_x : 0;
+ *y0 = r ? c.min_y : 0;
+ *x1 = r ? c.max_x : 0;
+ *y1 = r ? c.max_y : 0;
+ }
+ return r ? c.num_vertices : 0;
+}
+
+STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
+{
+ if (!info->cff.size)
+ return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);
+ else
+ return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);
+}
+
+STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)
+{
+ stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);
+ if (glyph_index < numOfLongHorMetrics) {
+ if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index);
+ if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);
+ } else {
+ if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));
+ if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
+ }
+}
+
+STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
+{
+ stbtt_uint8 *data = info->data + info->kern;
+ stbtt_uint32 needle, straw;
+ int l, r, m;
+
+ // we only look at the first table. it must be 'horizontal' and format 0.
+ if (!info->kern)
+ return 0;
+ if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
+ return 0;
+ if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
+ return 0;
+
+ l = 0;
+ r = ttUSHORT(data+10) - 1;
+ needle = glyph1 << 16 | glyph2;
+ while (l <= r) {
+ m = (l + r) >> 1;
+ straw = ttULONG(data+18+(m*6)); // note: unaligned read
+ if (needle < straw)
+ r = m - 1;
+ else if (needle > straw)
+ l = m + 1;
+ else
+ return ttSHORT(data+22+(m*6));
+ }
+ return 0;
+}
+
+STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)
+{
+ if (!info->kern) // if no kerning table, don't waste time looking up both codepoint->glyphs
+ return 0;
+ return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
+}
+
+STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)
+{
+ stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);
+}
+
+STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)
+{
+ if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4);
+ if (descent) *descent = ttSHORT(info->data+info->hhea + 6);
+ if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);
+}
+
+STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)
+{
+ *x0 = ttSHORT(info->data + info->head + 36);
+ *y0 = ttSHORT(info->data + info->head + 38);
+ *x1 = ttSHORT(info->data + info->head + 40);
+ *y1 = ttSHORT(info->data + info->head + 42);
+}
+
+STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)
+{
+ int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);
+ return (float) height / fheight;
+}
+
+STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels)
+{
+ int unitsPerEm = ttUSHORT(info->data + info->head + 18);
+ return pixels / unitsPerEm;
+}
+
+STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
+{
+ STBTT_free(v, info->userdata);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// antialiasing software rasterizer
+//
+
+STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
+{
+ int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning
+ if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
+ // e.g. space character
+ if (ix0) *ix0 = 0;
+ if (iy0) *iy0 = 0;
+ if (ix1) *ix1 = 0;
+ if (iy1) *iy1 = 0;
+ } else {
+ // move to integral bboxes (treating pixels as little squares, what pixels get touched)?
+ if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);
+ if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);
+ if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);
+ if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);
+ }
+}
+
+STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
+{
+ stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
+}
+
+STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
+{
+ stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);
+}
+
+STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
+{
+ stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Rasterizer
+
+typedef struct stbtt__hheap_chunk
+{
+ struct stbtt__hheap_chunk *next;
+} stbtt__hheap_chunk;
+
+typedef struct stbtt__hheap
+{
+ struct stbtt__hheap_chunk *head;
+ void *first_free;
+ int num_remaining_in_head_chunk;
+} stbtt__hheap;
+
+static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)
+{
+ if (hh->first_free) {
+ void *p = hh->first_free;
+ hh->first_free = * (void **) p;
+ return p;
+ } else {
+ if (hh->num_remaining_in_head_chunk == 0) {
+ int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);
+ stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);
+ if (c == NULL)
+ return NULL;
+ c->next = hh->head;
+ hh->head = c;
+ hh->num_remaining_in_head_chunk = count;
+ }
+ --hh->num_remaining_in_head_chunk;
+ return (char *) (hh->head) + size * hh->num_remaining_in_head_chunk;
+ }
+}
+
+static void stbtt__hheap_free(stbtt__hheap *hh, void *p)
+{
+ *(void **) p = hh->first_free;
+ hh->first_free = p;
+}
+
+static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)
+{
+ stbtt__hheap_chunk *c = hh->head;
+ while (c) {
+ stbtt__hheap_chunk *n = c->next;
+ STBTT_free(c, userdata);
+ c = n;
+ }
+}
+
+typedef struct stbtt__edge {
+ float x0,y0, x1,y1;
+ int invert;
+} stbtt__edge;
+
+
+typedef struct stbtt__active_edge
+{
+ struct stbtt__active_edge *next;
+ #if STBTT_RASTERIZER_VERSION==1
+ int x,dx;
+ float ey;
+ int direction;
+ #elif STBTT_RASTERIZER_VERSION==2
+ float fx,fdx,fdy;
+ float direction;
+ float sy;
+ float ey;
+ #else
+ #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
+ #endif
+} stbtt__active_edge;
+
+#if STBTT_RASTERIZER_VERSION == 1
+#define STBTT_FIXSHIFT 10
+#define STBTT_FIX (1 << STBTT_FIXSHIFT)
+#define STBTT_FIXMASK (STBTT_FIX-1)
+
+static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
+{
+ stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
+ float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
+ STBTT_assert(z != NULL);
+ if (!z) return z;
+
+ // round dx down to avoid overshooting
+ if (dxdy < 0)
+ z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);
+ else
+ z->dx = STBTT_ifloor(STBTT_FIX * dxdy);
+
+ z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount
+ z->x -= off_x * STBTT_FIX;
+
+ z->ey = e->y1;
+ z->next = 0;
+ z->direction = e->invert ? 1 : -1;
+ return z;
+}
+#elif STBTT_RASTERIZER_VERSION == 2
+static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
+{
+ stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
+ float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
+ STBTT_assert(z != NULL);
+ //STBTT_assert(e->y0 <= start_point);
+ if (!z) return z;
+ z->fdx = dxdy;
+ z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;
+ z->fx = e->x0 + dxdy * (start_point - e->y0);
+ z->fx -= off_x;
+ z->direction = e->invert ? 1.0f : -1.0f;
+ z->sy = e->y0;
+ z->ey = e->y1;
+ z->next = 0;
+ return z;
+}
+#else
+#error "Unrecognized value of STBTT_RASTERIZER_VERSION"
+#endif
+
+#if STBTT_RASTERIZER_VERSION == 1
+// note: this routine clips fills that extend off the edges... ideally this
+// wouldn't happen, but it could happen if the truetype glyph bounding boxes
+// are wrong, or if the user supplies a too-small bitmap
+static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)
+{
+ // non-zero winding fill
+ int x0=0, w=0;
+
+ while (e) {
+ if (w == 0) {
+ // if we're currently at zero, we need to record the edge start point
+ x0 = e->x; w += e->direction;
+ } else {
+ int x1 = e->x; w += e->direction;
+ // if we went to zero, we need to draw
+ if (w == 0) {
+ int i = x0 >> STBTT_FIXSHIFT;
+ int j = x1 >> STBTT_FIXSHIFT;
+
+ if (i < len && j >= 0) {
+ if (i == j) {
+ // x0,x1 are the same pixel, so compute combined coverage
+ scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);
+ } else {
+ if (i >= 0) // add antialiasing for x0
+ scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);
+ else
+ i = -1; // clip
+
+ if (j < len) // add antialiasing for x1
+ scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);
+ else
+ j = len; // clip
+
+ for (++i; i < j; ++i) // fill pixels between x0 and x1
+ scanline[i] = scanline[i] + (stbtt_uint8) max_weight;
+ }
+ }
+ }
+ }
+
+ e = e->next;
+ }
+}
+
+static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
+{
+ stbtt__hheap hh = { 0, 0, 0 };
+ stbtt__active_edge *active = NULL;
+ int y,j=0;
+ int max_weight = (255 / vsubsample); // weight per vertical scanline
+ int s; // vertical subsample index
+ unsigned char scanline_data[512], *scanline;
+
+ if (result->w > 512)
+ scanline = (unsigned char *) STBTT_malloc(result->w, userdata);
+ else
+ scanline = scanline_data;
+
+ y = off_y * vsubsample;
+ e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;
+
+ while (j < result->h) {
+ STBTT_memset(scanline, 0, result->w);
+ for (s=0; s < vsubsample; ++s) {
+ // find center of pixel for this scanline
+ float scan_y = y + 0.5f;
+ stbtt__active_edge **step = &active;
+
+ // update all active edges;
+ // remove all active edges that terminate before the center of this scanline
+ while (*step) {
+ stbtt__active_edge * z = *step;
+ if (z->ey <= scan_y) {
+ *step = z->next; // delete from list
+ STBTT_assert(z->direction);
+ z->direction = 0;
+ stbtt__hheap_free(&hh, z);
+ } else {
+ z->x += z->dx; // advance to position for current scanline
+ step = &((*step)->next); // advance through list
+ }
+ }
+
+ // resort the list if needed
+ for(;;) {
+ int changed=0;
+ step = &active;
+ while (*step && (*step)->next) {
+ if ((*step)->x > (*step)->next->x) {
+ stbtt__active_edge *t = *step;
+ stbtt__active_edge *q = t->next;
+
+ t->next = q->next;
+ q->next = t;
+ *step = q;
+ changed = 1;
+ }
+ step = &(*step)->next;
+ }
+ if (!changed) break;
+ }
+
+ // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
+ while (e->y0 <= scan_y) {
+ if (e->y1 > scan_y) {
+ stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);
+ if (z != NULL) {
+ // find insertion point
+ if (active == NULL)
+ active = z;
+ else if (z->x < active->x) {
+ // insert at front
+ z->next = active;
+ active = z;
+ } else {
+ // find thing to insert AFTER
+ stbtt__active_edge *p = active;
+ while (p->next && p->next->x < z->x)
+ p = p->next;
+ // at this point, p->next->x is NOT < z->x
+ z->next = p->next;
+ p->next = z;
+ }
+ }
+ }
+ ++e;
+ }
+
+ // now process all active edges in XOR fashion
+ if (active)
+ stbtt__fill_active_edges(scanline, result->w, active, max_weight);
+
+ ++y;
+ }
+ STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);
+ ++j;
+ }
+
+ stbtt__hheap_cleanup(&hh, userdata);
+
+ if (scanline != scanline_data)
+ STBTT_free(scanline, userdata);
+}
+
+#elif STBTT_RASTERIZER_VERSION == 2
+
+// the edge passed in here does not cross the vertical line at x or the vertical line at x+1
+// (i.e. it has already been clipped to those)
+static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)
+{
+ if (y0 == y1) return;
+ STBTT_assert(y0 < y1);
+ STBTT_assert(e->sy <= e->ey);
+ if (y0 > e->ey) return;
+ if (y1 < e->sy) return;
+ if (y0 < e->sy) {
+ x0 += (x1-x0) * (e->sy - y0) / (y1-y0);
+ y0 = e->sy;
+ }
+ if (y1 > e->ey) {
+ x1 += (x1-x0) * (e->ey - y1) / (y1-y0);
+ y1 = e->ey;
+ }
+
+ if (x0 == x)
+ STBTT_assert(x1 <= x+1);
+ else if (x0 == x+1)
+ STBTT_assert(x1 >= x);
+ else if (x0 <= x)
+ STBTT_assert(x1 <= x);
+ else if (x0 >= x+1)
+ STBTT_assert(x1 >= x+1);
+ else
+ STBTT_assert(x1 >= x && x1 <= x+1);
+
+ if (x0 <= x && x1 <= x)
+ scanline[x] += e->direction * (y1-y0);
+ else if (x0 >= x+1 && x1 >= x+1)
+ ;
+ else {
+ STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);
+ scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position
+ }
+}
+
+static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
+{
+ float y_bottom = y_top+1;
+
+ while (e) {
+ // brute force every pixel
+
+ // compute intersection points with top & bottom
+ STBTT_assert(e->ey >= y_top);
+
+ if (e->fdx == 0) {
+ float x0 = e->fx;
+ if (x0 < len) {
+ if (x0 >= 0) {
+ stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);
+ stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);
+ } else {
+ stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);
+ }
+ }
+ } else {
+ float x0 = e->fx;
+ float dx = e->fdx;
+ float xb = x0 + dx;
+ float x_top, x_bottom;
+ float sy0,sy1;
+ float dy = e->fdy;
+ STBTT_assert(e->sy <= y_bottom && e->ey >= y_top);
+
+ // compute endpoints of line segment clipped to this scanline (if the
+ // line segment starts on this scanline. x0 is the intersection of the
+ // line with y_top, but that may be off the line segment.
+ if (e->sy > y_top) {
+ x_top = x0 + dx * (e->sy - y_top);
+ sy0 = e->sy;
+ } else {
+ x_top = x0;
+ sy0 = y_top;
+ }
+ if (e->ey < y_bottom) {
+ x_bottom = x0 + dx * (e->ey - y_top);
+ sy1 = e->ey;
+ } else {
+ x_bottom = xb;
+ sy1 = y_bottom;
+ }
+
+ if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {
+ // from here on, we don't have to range check x values
+
+ if ((int) x_top == (int) x_bottom) {
+ float height;
+ // simple case, only spans one pixel
+ int x = (int) x_top;
+ height = sy1 - sy0;
+ STBTT_assert(x >= 0 && x < len);
+ scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height;
+ scanline_fill[x] += e->direction * height; // everything right of this pixel is filled
+ } else {
+ int x,x1,x2;
+ float y_crossing, step, sign, area;
+ // covers 2+ pixels
+ if (x_top > x_bottom) {
+ // flip scanline vertically; signed area is the same
+ float t;
+ sy0 = y_bottom - (sy0 - y_top);
+ sy1 = y_bottom - (sy1 - y_top);
+ t = sy0, sy0 = sy1, sy1 = t;
+ t = x_bottom, x_bottom = x_top, x_top = t;
+ dx = -dx;
+ dy = -dy;
+ t = x0, x0 = xb, xb = t;
+ }
+
+ x1 = (int) x_top;
+ x2 = (int) x_bottom;
+ // compute intersection with y axis at x1+1
+ y_crossing = (x1+1 - x0) * dy + y_top;
+
+ sign = e->direction;
+ // area of the rectangle covered from y0..y_crossing
+ area = sign * (y_crossing-sy0);
+ // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
+ scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);
+
+ step = sign * dy;
+ for (x = x1+1; x < x2; ++x) {
+ scanline[x] += area + step/2;
+ area += step;
+ }
+ y_crossing += dy * (x2 - (x1+1));
+
+ STBTT_assert(STBTT_fabs(area) <= 1.01f);
+
+ scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);
+
+ scanline_fill[x2] += sign * (sy1-sy0);
+ }
+ } else {
+ // if edge goes outside of box we're drawing, we require
+ // clipping logic. since this does not match the intended use
+ // of this library, we use a different, very slow brute
+ // force implementation
+ int x;
+ for (x=0; x < len; ++x) {
+ // cases:
+ //
+ // there can be up to two intersections with the pixel. any intersection
+ // with left or right edges can be handled by splitting into two (or three)
+ // regions. intersections with top & bottom do not necessitate case-wise logic.
+ //
+ // the old way of doing this found the intersections with the left & right edges,
+ // then used some simple logic to produce up to three segments in sorted order
+ // from top-to-bottom. however, this had a problem: if an x edge was epsilon
+ // across the x border, then the corresponding y position might not be distinct
+ // from the other y segment, and it might ignored as an empty segment. to avoid
+ // that, we need to explicitly produce segments based on x positions.
+
+ // rename variables to clear pairs
+ float y0 = y_top;
+ float x1 = (float) (x);
+ float x2 = (float) (x+1);
+ float x3 = xb;
+ float y3 = y_bottom;
+ float y1,y2;
+
+ // x = e->x + e->dx * (y-y_top)
+ // (y-y_top) = (x - e->x) / e->dx
+ // y = (x - e->x) / e->dx + y_top
+ y1 = (x - x0) / dx + y_top;
+ y2 = (x+1 - x0) / dx + y_top;
+
+ if (x0 < x1 && x3 > x2) { // three segments descending down-right
+ stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
+ stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);
+ stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
+ } else if (x3 < x1 && x0 > x2) { // three segments descending down-left
+ stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
+ stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);
+ stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
+ } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right
+ stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
+ stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
+ } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left
+ stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
+ stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
+ } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right
+ stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
+ stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
+ } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left
+ stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
+ stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
+ } else { // one segment
+ stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);
+ }
+ }
+ }
+ }
+ e = e->next;
+ }
+}
+
+// directly AA rasterize edges w/o supersampling
+static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
+{
+ stbtt__hheap hh = { 0, 0, 0 };
+ stbtt__active_edge *active = NULL;
+ int y,j=0, i;
+ float scanline_data[129], *scanline, *scanline2;
+
+ STBTT__NOTUSED(vsubsample);
+
+ if (result->w > 64)
+ scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);
+ else
+ scanline = scanline_data;
+
+ scanline2 = scanline + result->w;
+
+ y = off_y;
+ e[n].y0 = (float) (off_y + result->h) + 1;
+
+ while (j < result->h) {
+ // find center of pixel for this scanline
+ float scan_y_top = y + 0.0f;
+ float scan_y_bottom = y + 1.0f;
+ stbtt__active_edge **step = &active;
+
+ STBTT_memset(scanline , 0, result->w*sizeof(scanline[0]));
+ STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0]));
+
+ // update all active edges;
+ // remove all active edges that terminate before the top of this scanline
+ while (*step) {
+ stbtt__active_edge * z = *step;
+ if (z->ey <= scan_y_top) {
+ *step = z->next; // delete from list
+ STBTT_assert(z->direction);
+ z->direction = 0;
+ stbtt__hheap_free(&hh, z);
+ } else {
+ step = &((*step)->next); // advance through list
+ }
+ }
+
+ // insert all edges that start before the bottom of this scanline
+ while (e->y0 <= scan_y_bottom) {
+ if (e->y0 != e->y1) {
+ stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
+ if (z != NULL) {
+ STBTT_assert(z->ey >= scan_y_top);
+ // insert at front
+ z->next = active;
+ active = z;
+ }
+ }
+ ++e;
+ }
+
+ // now process all active edges
+ if (active)
+ stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);
+
+ {
+ float sum = 0;
+ for (i=0; i < result->w; ++i) {
+ float k;
+ int m;
+ sum += scanline2[i];
+ k = scanline[i] + sum;
+ k = (float) STBTT_fabs(k)*255 + 0.5f;
+ m = (int) k;
+ if (m > 255) m = 255;
+ result->pixels[j*result->stride + i] = (unsigned char) m;
+ }
+ }
+ // advance all the edges
+ step = &active;
+ while (*step) {
+ stbtt__active_edge *z = *step;
+ z->fx += z->fdx; // advance to position for current scanline
+ step = &((*step)->next); // advance through list
+ }
+
+ ++y;
+ ++j;
+ }
+
+ stbtt__hheap_cleanup(&hh, userdata);
+
+ if (scanline != scanline_data)
+ STBTT_free(scanline, userdata);
+}
+#else
+#error "Unrecognized value of STBTT_RASTERIZER_VERSION"
+#endif
+
+#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0)
+
+static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)
+{
+ int i,j;
+ for (i=1; i < n; ++i) {
+ stbtt__edge t = p[i], *a = &t;
+ j = i;
+ while (j > 0) {
+ stbtt__edge *b = &p[j-1];
+ int c = STBTT__COMPARE(a,b);
+ if (!c) break;
+ p[j] = p[j-1];
+ --j;
+ }
+ if (i != j)
+ p[j] = t;
+ }
+}
+
+static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
+{
+ /* threshhold for transitioning to insertion sort */
+ while (n > 12) {
+ stbtt__edge t;
+ int c01,c12,c,m,i,j;
+
+ /* compute median of three */
+ m = n >> 1;
+ c01 = STBTT__COMPARE(&p[0],&p[m]);
+ c12 = STBTT__COMPARE(&p[m],&p[n-1]);
+ /* if 0 >= mid >= end, or 0 < mid < end, then use mid */
+ if (c01 != c12) {
+ /* otherwise, we'll need to swap something else to middle */
+ int z;
+ c = STBTT__COMPARE(&p[0],&p[n-1]);
+ /* 0>mid && mid<n: 0>n => n; 0<n => 0 */
+ /* 0<mid && mid>n: 0>n => 0; 0<n => n */
+ z = (c == c12) ? 0 : n-1;
+ t = p[z];
+ p[z] = p[m];
+ p[m] = t;
+ }
+ /* now p[m] is the median-of-three */
+ /* swap it to the beginning so it won't move around */
+ t = p[0];
+ p[0] = p[m];
+ p[m] = t;
+
+ /* partition loop */
+ i=1;
+ j=n-1;
+ for(;;) {
+ /* handling of equality is crucial here */
+ /* for sentinels & efficiency with duplicates */
+ for (;;++i) {
+ if (!STBTT__COMPARE(&p[i], &p[0])) break;
+ }
+ for (;;--j) {
+ if (!STBTT__COMPARE(&p[0], &p[j])) break;
+ }
+ /* make sure we haven't crossed */
+ if (i >= j) break;
+ t = p[i];
+ p[i] = p[j];
+ p[j] = t;
+
+ ++i;
+ --j;
+ }
+ /* recurse on smaller side, iterate on larger */
+ if (j < (n-i)) {
+ stbtt__sort_edges_quicksort(p,j);
+ p = p+i;
+ n = n-i;
+ } else {
+ stbtt__sort_edges_quicksort(p+i, n-i);
+ n = j;
+ }
+ }
+}
+
+static void stbtt__sort_edges(stbtt__edge *p, int n)
+{
+ stbtt__sort_edges_quicksort(p, n);
+ stbtt__sort_edges_ins_sort(p, n);
+}
+
+typedef struct
+{
+ float x,y;
+} stbtt__point;
+
+static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata)
+{
+ float y_scale_inv = invert ? -scale_y : scale_y;
+ stbtt__edge *e;
+ int n,i,j,k,m;
+#if STBTT_RASTERIZER_VERSION == 1
+ int vsubsample = result->h < 8 ? 15 : 5;
+#elif STBTT_RASTERIZER_VERSION == 2
+ int vsubsample = 1;
+#else
+ #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
+#endif
+ // vsubsample should divide 255 evenly; otherwise we won't reach full opacity
+
+ // now we have to blow out the windings into explicit edge lists
+ n = 0;
+ for (i=0; i < windings; ++i)
+ n += wcount[i];
+
+ e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel
+ if (e == 0) return;
+ n = 0;
+
+ m=0;
+ for (i=0; i < windings; ++i) {
+ stbtt__point *p = pts + m;
+ m += wcount[i];
+ j = wcount[i]-1;
+ for (k=0; k < wcount[i]; j=k++) {
+ int a=k,b=j;
+ // skip the edge if horizontal
+ if (p[j].y == p[k].y)
+ continue;
+ // add edge from j to k to the list
+ e[n].invert = 0;
+ if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {
+ e[n].invert = 1;
+ a=j,b=k;
+ }
+ e[n].x0 = p[a].x * scale_x + shift_x;
+ e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;
+ e[n].x1 = p[b].x * scale_x + shift_x;
+ e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;
+ ++n;
+ }
+ }
+
+ // now sort the edges by their highest point (should snap to integer, and then by x)
+ //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare);
+ stbtt__sort_edges(e, n);
+
+ // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule
+ stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);
+
+ STBTT_free(e, userdata);
+}
+
+static void stbtt__add_point(stbtt__point *points, int n, float x, float y)
+{
+ if (!points) return; // during first pass, it's unallocated
+ points[n].x = x;
+ points[n].y = y;
+}
+
+// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching
+static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)
+{
+ // midpoint
+ float mx = (x0 + 2*x1 + x2)/4;
+ float my = (y0 + 2*y1 + y2)/4;
+ // versus directly drawn line
+ float dx = (x0+x2)/2 - mx;
+ float dy = (y0+y2)/2 - my;
+ if (n > 16) // 65536 segments on one curve better be enough!
+ return 1;
+ if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA
+ stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);
+ stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);
+ } else {
+ stbtt__add_point(points, *num_points,x2,y2);
+ *num_points = *num_points+1;
+ }
+ return 1;
+}
+
+static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n)
+{
+ // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough
+ float dx0 = x1-x0;
+ float dy0 = y1-y0;
+ float dx1 = x2-x1;
+ float dy1 = y2-y1;
+ float dx2 = x3-x2;
+ float dy2 = y3-y2;
+ float dx = x3-x0;
+ float dy = y3-y0;
+ float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));
+ float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);
+ float flatness_squared = longlen*longlen-shortlen*shortlen;
+
+ if (n > 16) // 65536 segments on one curve better be enough!
+ return;
+
+ if (flatness_squared > objspace_flatness_squared) {
+ float x01 = (x0+x1)/2;
+ float y01 = (y0+y1)/2;
+ float x12 = (x1+x2)/2;
+ float y12 = (y1+y2)/2;
+ float x23 = (x2+x3)/2;
+ float y23 = (y2+y3)/2;
+
+ float xa = (x01+x12)/2;
+ float ya = (y01+y12)/2;
+ float xb = (x12+x23)/2;
+ float yb = (y12+y23)/2;
+
+ float mx = (xa+xb)/2;
+ float my = (ya+yb)/2;
+
+ stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);
+ stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);
+ } else {
+ stbtt__add_point(points, *num_points,x3,y3);
+ *num_points = *num_points+1;
+ }
+}
+
+// returns number of contours
+static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
+{
+ stbtt__point *points=0;
+ int num_points=0;
+
+ float objspace_flatness_squared = objspace_flatness * objspace_flatness;
+ int i,n=0,start=0, pass;
+
+ // count how many "moves" there are to get the contour count
+ for (i=0; i < num_verts; ++i)
+ if (vertices[i].type == STBTT_vmove)
+ ++n;
+
+ *num_contours = n;
+ if (n == 0) return 0;
+
+ *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);
+
+ if (*contour_lengths == 0) {
+ *num_contours = 0;
+ return 0;
+ }
+
+ // make two passes through the points so we don't need to realloc
+ for (pass=0; pass < 2; ++pass) {
+ float x=0,y=0;
+ if (pass == 1) {
+ points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);
+ if (points == NULL) goto error;
+ }
+ num_points = 0;
+ n= -1;
+ for (i=0; i < num_verts; ++i) {
+ switch (vertices[i].type) {
+ case STBTT_vmove:
+ // start the next contour
+ if (n >= 0)
+ (*contour_lengths)[n] = num_points - start;
+ ++n;
+ start = num_points;
+
+ x = vertices[i].x, y = vertices[i].y;
+ stbtt__add_point(points, num_points++, x,y);
+ break;
+ case STBTT_vline:
+ x = vertices[i].x, y = vertices[i].y;
+ stbtt__add_point(points, num_points++, x, y);
+ break;
+ case STBTT_vcurve:
+ stbtt__tesselate_curve(points, &num_points, x,y,
+ vertices[i].cx, vertices[i].cy,
+ vertices[i].x, vertices[i].y,
+ objspace_flatness_squared, 0);
+ x = vertices[i].x, y = vertices[i].y;
+ break;
+ case STBTT_vcubic:
+ stbtt__tesselate_cubic(points, &num_points, x,y,
+ vertices[i].cx, vertices[i].cy,
+ vertices[i].cx1, vertices[i].cy1,
+ vertices[i].x, vertices[i].y,
+ objspace_flatness_squared, 0);
+ x = vertices[i].x, y = vertices[i].y;
+ break;
+ }
+ }
+ (*contour_lengths)[n] = num_points - start;
+ }
+
+ return points;
+error:
+ STBTT_free(points, userdata);
+ STBTT_free(*contour_lengths, userdata);
+ *contour_lengths = 0;
+ *num_contours = 0;
+ return NULL;
+}
+
+STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
+{
+ float scale = scale_x > scale_y ? scale_y : scale_x;
+ int winding_count, *winding_lengths;
+ stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
+ if (windings) {
+ stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
+ STBTT_free(winding_lengths, userdata);
+ STBTT_free(windings, userdata);
+ }
+}
+
+STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)
+{
+ STBTT_free(bitmap, userdata);
+}
+
+STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)
+{
+ int ix0,iy0,ix1,iy1;
+ stbtt__bitmap gbm;
+ stbtt_vertex *vertices;
+ int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
+
+ if (scale_x == 0) scale_x = scale_y;
+ if (scale_y == 0) {
+ if (scale_x == 0) {
+ STBTT_free(vertices, info->userdata);
+ return NULL;
+ }
+ scale_y = scale_x;
+ }
+
+ stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);
+
+ // now we get the size
+ gbm.w = (ix1 - ix0);
+ gbm.h = (iy1 - iy0);
+ gbm.pixels = NULL; // in case we error
+
+ if (width ) *width = gbm.w;
+ if (height) *height = gbm.h;
+ if (xoff ) *xoff = ix0;
+ if (yoff ) *yoff = iy0;
+
+ if (gbm.w && gbm.h) {
+ gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);
+ if (gbm.pixels) {
+ gbm.stride = gbm.w;
+
+ stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);
+ }
+ }
+ STBTT_free(vertices, info->userdata);
+ return gbm.pixels;
+}
+
+STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
+{
+ return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);
+}
+
+STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)
+{
+ int ix0,iy0;
+ stbtt_vertex *vertices;
+ int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
+ stbtt__bitmap gbm;
+
+ stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);
+ gbm.pixels = output;
+ gbm.w = out_w;
+ gbm.h = out_h;
+ gbm.stride = out_stride;
+
+ if (gbm.w && gbm.h)
+ stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);
+
+ STBTT_free(vertices, info->userdata);
+}
+
+STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)
+{
+ stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);
+}
+
+STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
+{
+ return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
+}
+
+STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)
+{
+ stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
+}
+
+STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
+{
+ return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
+}
+
+STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)
+{
+ stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// bitmap baking
+//
+// This is SUPER-CRAPPY packing to keep source code small
+
+static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf)
+ float pixel_height, // height of font in pixels
+ unsigned char *pixels, int pw, int ph, // bitmap to be filled in
+ int first_char, int num_chars, // characters to bake
+ stbtt_bakedchar *chardata)
+{
+ float scale;
+ int x,y,bottom_y, i;
+ stbtt_fontinfo f;
+ f.userdata = NULL;
+ if (!stbtt_InitFont(&f, data, offset))
+ return -1;
+ STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
+ x=y=1;
+ bottom_y = 1;
+
+ scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
+
+ for (i=0; i < num_chars; ++i) {
+ int advance, lsb, x0,y0,x1,y1,gw,gh;
+ int g = stbtt_FindGlyphIndex(&f, first_char + i);
+ stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
+ stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);
+ gw = x1-x0;
+ gh = y1-y0;
+ if (x + gw + 1 >= pw)
+ y = bottom_y, x = 1; // advance to next row
+ if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row
+ return -i;
+ STBTT_assert(x+gw < pw);
+ STBTT_assert(y+gh < ph);
+ stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);
+ chardata[i].x0 = (stbtt_int16) x;
+ chardata[i].y0 = (stbtt_int16) y;
+ chardata[i].x1 = (stbtt_int16) (x + gw);
+ chardata[i].y1 = (stbtt_int16) (y + gh);
+ chardata[i].xadvance = scale * advance;
+ chardata[i].xoff = (float) x0;
+ chardata[i].yoff = (float) y0;
+ x = x + gw + 1;
+ if (y+gh+1 > bottom_y)
+ bottom_y = y+gh+1;
+ }
+ return bottom_y;
+}
+
+STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)
+{
+ float d3d_bias = opengl_fillrule ? 0 : -0.5f;
+ float ipw = 1.0f / pw, iph = 1.0f / ph;
+ stbtt_bakedchar *b = chardata + char_index;
+ int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);
+ int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);
+
+ q->x0 = round_x + d3d_bias;
+ q->y0 = round_y + d3d_bias;
+ q->x1 = round_x + b->x1 - b->x0 + d3d_bias;
+ q->y1 = round_y + b->y1 - b->y0 + d3d_bias;
+
+ q->s0 = b->x0 * ipw;
+ q->t0 = b->y0 * iph;
+ q->s1 = b->x1 * ipw;
+ q->t1 = b->y1 * iph;
+
+ *xpos += b->xadvance;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// rectangle packing replacement routines if you don't have stb_rect_pack.h
+//
+
+#ifndef STB_RECT_PACK_VERSION
+
+typedef int stbrp_coord;
+
+////////////////////////////////////////////////////////////////////////////////////
+// //
+// //
+// COMPILER WARNING ?!?!? //
+// //
+// //
+// if you get a compile warning due to these symbols being defined more than //
+// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct
+{
+ int width,height;
+ int x,y,bottom_y;
+} stbrp_context;
+
+typedef struct
+{
+ unsigned char x;
+} stbrp_node;
+
+struct stbrp_rect
+{
+ stbrp_coord x,y;
+ int id,w,h,was_packed;
+};
+
+static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)
+{
+ con->width = pw;
+ con->height = ph;
+ con->x = 0;
+ con->y = 0;
+ con->bottom_y = 0;
+ STBTT__NOTUSED(nodes);
+ STBTT__NOTUSED(num_nodes);
+}
+
+static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)
+{
+ int i;
+ for (i=0; i < num_rects; ++i) {
+ if (con->x + rects[i].w > con->width) {
+ con->x = 0;
+ con->y = con->bottom_y;
+ }
+ if (con->y + rects[i].h > con->height)
+ break;
+ rects[i].x = con->x;
+ rects[i].y = con->y;
+ rects[i].was_packed = 1;
+ con->x += rects[i].w;
+ if (con->y + rects[i].h > con->bottom_y)
+ con->bottom_y = con->y + rects[i].h;
+ }
+ for ( ; i < num_rects; ++i)
+ rects[i].was_packed = 0;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// bitmap baking
+//
+// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If
+// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy.
+
+STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)
+{
+ stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context);
+ int num_nodes = pw - padding;
+ stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context);
+
+ if (context == NULL || nodes == NULL) {
+ if (context != NULL) STBTT_free(context, alloc_context);
+ if (nodes != NULL) STBTT_free(nodes , alloc_context);
+ return 0;
+ }
+
+ spc->user_allocator_context = alloc_context;
+ spc->width = pw;
+ spc->height = ph;
+ spc->pixels = pixels;
+ spc->pack_info = context;
+ spc->nodes = nodes;
+ spc->padding = padding;
+ spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;
+ spc->h_oversample = 1;
+ spc->v_oversample = 1;
+
+ stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
+
+ if (pixels)
+ STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
+
+ return 1;
+}
+
+STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc)
+{
+ STBTT_free(spc->nodes , spc->user_allocator_context);
+ STBTT_free(spc->pack_info, spc->user_allocator_context);
+}
+
+STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample)
+{
+ STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE);
+ STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE);
+ if (h_oversample <= STBTT_MAX_OVERSAMPLE)
+ spc->h_oversample = h_oversample;
+ if (v_oversample <= STBTT_MAX_OVERSAMPLE)
+ spc->v_oversample = v_oversample;
+}
+
+#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1)
+
+static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
+{
+ unsigned char buffer[STBTT_MAX_OVERSAMPLE];
+ int safe_w = w - kernel_width;
+ int j;
+ STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
+ for (j=0; j < h; ++j) {
+ int i;
+ unsigned int total;
+ STBTT_memset(buffer, 0, kernel_width);
+
+ total = 0;
+
+ // make kernel_width a constant in common cases so compiler can optimize out the divide
+ switch (kernel_width) {
+ case 2:
+ for (i=0; i <= safe_w; ++i) {
+ total += pixels[i] - buffer[i & STBTT__OVER_MASK];
+ buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
+ pixels[i] = (unsigned char) (total / 2);
+ }
+ break;
+ case 3:
+ for (i=0; i <= safe_w; ++i) {
+ total += pixels[i] - buffer[i & STBTT__OVER_MASK];
+ buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
+ pixels[i] = (unsigned char) (total / 3);
+ }
+ break;
+ case 4:
+ for (i=0; i <= safe_w; ++i) {
+ total += pixels[i] - buffer[i & STBTT__OVER_MASK];
+ buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
+ pixels[i] = (unsigned char) (total / 4);
+ }
+ break;
+ case 5:
+ for (i=0; i <= safe_w; ++i) {
+ total += pixels[i] - buffer[i & STBTT__OVER_MASK];
+ buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
+ pixels[i] = (unsigned char) (total / 5);
+ }
+ break;
+ default:
+ for (i=0; i <= safe_w; ++i) {
+ total += pixels[i] - buffer[i & STBTT__OVER_MASK];
+ buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
+ pixels[i] = (unsigned char) (total / kernel_width);
+ }
+ break;
+ }
+
+ for (; i < w; ++i) {
+ STBTT_assert(pixels[i] == 0);
+ total -= buffer[i & STBTT__OVER_MASK];
+ pixels[i] = (unsigned char) (total / kernel_width);
+ }
+
+ pixels += stride_in_bytes;
+ }
+}
+
+static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
+{
+ unsigned char buffer[STBTT_MAX_OVERSAMPLE];
+ int safe_h = h - kernel_width;
+ int j;
+ STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
+ for (j=0; j < w; ++j) {
+ int i;
+ unsigned int total;
+ STBTT_memset(buffer, 0, kernel_width);
+
+ total = 0;
+
+ // make kernel_width a constant in common cases so compiler can optimize out the divide
+ switch (kernel_width) {
+ case 2:
+ for (i=0; i <= safe_h; ++i) {
+ total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
+ buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
+ pixels[i*stride_in_bytes] = (unsigned char) (total / 2);
+ }
+ break;
+ case 3:
+ for (i=0; i <= safe_h; ++i) {
+ total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
+ buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
+ pixels[i*stride_in_bytes] = (unsigned char) (total / 3);
+ }
+ break;
+ case 4:
+ for (i=0; i <= safe_h; ++i) {
+ total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
+ buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
+ pixels[i*stride_in_bytes] = (unsigned char) (total / 4);
+ }
+ break;
+ case 5:
+ for (i=0; i <= safe_h; ++i) {
+ total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
+ buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
+ pixels[i*stride_in_bytes] = (unsigned char) (total / 5);
+ }
+ break;
+ default:
+ for (i=0; i <= safe_h; ++i) {
+ total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
+ buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
+ pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);
+ }
+ break;
+ }
+
+ for (; i < h; ++i) {
+ STBTT_assert(pixels[i*stride_in_bytes] == 0);
+ total -= buffer[i & STBTT__OVER_MASK];
+ pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);
+ }
+
+ pixels += 1;
+ }
+}
+
+static float stbtt__oversample_shift(int oversample)
+{
+ if (!oversample)
+ return 0.0f;
+
+ // The prefilter is a box filter of width "oversample",
+ // which shifts phase by (oversample - 1)/2 pixels in
+ // oversampled space. We want to shift in the opposite
+ // direction to counter this.
+ return (float)-(oversample - 1) / (2.0f * (float)oversample);
+}
+
+// rects array must be big enough to accommodate all characters in the given ranges
+STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
+{
+ int i,j,k;
+
+ k=0;
+ for (i=0; i < num_ranges; ++i) {
+ float fh = ranges[i].font_size;
+ float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
+ ranges[i].h_oversample = (unsigned char) spc->h_oversample;
+ ranges[i].v_oversample = (unsigned char) spc->v_oversample;
+ for (j=0; j < ranges[i].num_chars; ++j) {
+ int x0,y0,x1,y1;
+ int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
+ int glyph = stbtt_FindGlyphIndex(info, codepoint);
+ stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
+ scale * spc->h_oversample,
+ scale * spc->v_oversample,
+ 0,0,
+ &x0,&y0,&x1,&y1);
+ rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
+ rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
+ ++k;
+ }
+ }
+
+ return k;
+}
+
+// rects array must be big enough to accommodate all characters in the given ranges
+STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
+{
+ int i,j,k, return_value = 1;
+
+ // save current values
+ int old_h_over = spc->h_oversample;
+ int old_v_over = spc->v_oversample;
+
+ k = 0;
+ for (i=0; i < num_ranges; ++i) {
+ float fh = ranges[i].font_size;
+ float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
+ float recip_h,recip_v,sub_x,sub_y;
+ spc->h_oversample = ranges[i].h_oversample;
+ spc->v_oversample = ranges[i].v_oversample;
+ recip_h = 1.0f / spc->h_oversample;
+ recip_v = 1.0f / spc->v_oversample;
+ sub_x = stbtt__oversample_shift(spc->h_oversample);
+ sub_y = stbtt__oversample_shift(spc->v_oversample);
+ for (j=0; j < ranges[i].num_chars; ++j) {
+ stbrp_rect *r = &rects[k];
+ if (r->was_packed) {
+ stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
+ int advance, lsb, x0,y0,x1,y1;
+ int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
+ int glyph = stbtt_FindGlyphIndex(info, codepoint);
+ stbrp_coord pad = (stbrp_coord) spc->padding;
+
+ // pad on left and top
+ r->x += pad;
+ r->y += pad;
+ r->w -= pad;
+ r->h -= pad;
+ stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);
+ stbtt_GetGlyphBitmapBox(info, glyph,
+ scale * spc->h_oversample,
+ scale * spc->v_oversample,
+ &x0,&y0,&x1,&y1);
+ stbtt_MakeGlyphBitmapSubpixel(info,
+ spc->pixels + r->x + r->y*spc->stride_in_bytes,
+ r->w - spc->h_oversample+1,
+ r->h - spc->v_oversample+1,
+ spc->stride_in_bytes,
+ scale * spc->h_oversample,
+ scale * spc->v_oversample,
+ 0,0,
+ glyph);
+
+ if (spc->h_oversample > 1)
+ stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
+ r->w, r->h, spc->stride_in_bytes,
+ spc->h_oversample);
+
+ if (spc->v_oversample > 1)
+ stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
+ r->w, r->h, spc->stride_in_bytes,
+ spc->v_oversample);
+
+ bc->x0 = (stbtt_int16) r->x;
+ bc->y0 = (stbtt_int16) r->y;
+ bc->x1 = (stbtt_int16) (r->x + r->w);
+ bc->y1 = (stbtt_int16) (r->y + r->h);
+ bc->xadvance = scale * advance;
+ bc->xoff = (float) x0 * recip_h + sub_x;
+ bc->yoff = (float) y0 * recip_v + sub_y;
+ bc->xoff2 = (x0 + r->w) * recip_h + sub_x;
+ bc->yoff2 = (y0 + r->h) * recip_v + sub_y;
+ } else {
+ return_value = 0; // if any fail, report failure
+ }
+
+ ++k;
+ }
+ }
+
+ // restore original values
+ spc->h_oversample = old_h_over;
+ spc->v_oversample = old_v_over;
+
+ return return_value;
+}
+
+STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)
+{
+ stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);
+}
+
+STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
+{
+ stbtt_fontinfo info;
+ int i,j,n, return_value = 1;
+ //stbrp_context *context = (stbrp_context *) spc->pack_info;
+ stbrp_rect *rects;
+
+ // flag all characters as NOT packed
+ for (i=0; i < num_ranges; ++i)
+ for (j=0; j < ranges[i].num_chars; ++j)
+ ranges[i].chardata_for_range[j].x0 =
+ ranges[i].chardata_for_range[j].y0 =
+ ranges[i].chardata_for_range[j].x1 =
+ ranges[i].chardata_for_range[j].y1 = 0;
+
+ n = 0;
+ for (i=0; i < num_ranges; ++i)
+ n += ranges[i].num_chars;
+
+ rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);
+ if (rects == NULL)
+ return 0;
+
+ info.userdata = spc->user_allocator_context;
+ stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));
+
+ n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
+
+ stbtt_PackFontRangesPackRects(spc, rects, n);
+
+ return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);
+
+ STBTT_free(rects, spc->user_allocator_context);
+ return return_value;
+}
+
+STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size,
+ int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
+{
+ stbtt_pack_range range;
+ range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;
+ range.array_of_unicode_codepoints = NULL;
+ range.num_chars = num_chars_in_range;
+ range.chardata_for_range = chardata_for_range;
+ range.font_size = font_size;
+ return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
+}
+
+STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)
+{
+ float ipw = 1.0f / pw, iph = 1.0f / ph;
+ stbtt_packedchar *b = chardata + char_index;
+
+ if (align_to_integer) {
+ float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);
+ float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);
+ q->x0 = x;
+ q->y0 = y;
+ q->x1 = x + b->xoff2 - b->xoff;
+ q->y1 = y + b->yoff2 - b->yoff;
+ } else {
+ q->x0 = *xpos + b->xoff;
+ q->y0 = *ypos + b->yoff;
+ q->x1 = *xpos + b->xoff2;
+ q->y1 = *ypos + b->yoff2;
+ }
+
+ q->s0 = b->x0 * ipw;
+ q->t0 = b->y0 * iph;
+ q->s1 = b->x1 * ipw;
+ q->t1 = b->y1 * iph;
+
+ *xpos += b->xadvance;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// font name matching -- recommended not to use this
+//
+
+// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string
+static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
+{
+ stbtt_int32 i=0;
+
+ // convert utf16 to utf8 and compare the results while converting
+ while (len2) {
+ stbtt_uint16 ch = s2[0]*256 + s2[1];
+ if (ch < 0x80) {
+ if (i >= len1) return -1;
+ if (s1[i++] != ch) return -1;
+ } else if (ch < 0x800) {
+ if (i+1 >= len1) return -1;
+ if (s1[i++] != 0xc0 + (ch >> 6)) return -1;
+ if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;
+ } else if (ch >= 0xd800 && ch < 0xdc00) {
+ stbtt_uint32 c;
+ stbtt_uint16 ch2 = s2[2]*256 + s2[3];
+ if (i+3 >= len1) return -1;
+ c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
+ if (s1[i++] != 0xf0 + (c >> 18)) return -1;
+ if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;
+ if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1;
+ if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1;
+ s2 += 2; // plus another 2 below
+ len2 -= 2;
+ } else if (ch >= 0xdc00 && ch < 0xe000) {
+ return -1;
+ } else {
+ if (i+2 >= len1) return -1;
+ if (s1[i++] != 0xe0 + (ch >> 12)) return -1;
+ if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;
+ if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1;
+ }
+ s2 += 2;
+ len2 -= 2;
+ }
+ return i;
+}
+
+static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)
+{
+ return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);
+}
+
+// returns results in whatever encoding you request... but note that 2-byte encodings
+// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare
+STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)
+{
+ stbtt_int32 i,count,stringOffset;
+ stbtt_uint8 *fc = font->data;
+ stbtt_uint32 offset = font->fontstart;
+ stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");
+ if (!nm) return NULL;
+
+ count = ttUSHORT(fc+nm+2);
+ stringOffset = nm + ttUSHORT(fc+nm+4);
+ for (i=0; i < count; ++i) {
+ stbtt_uint32 loc = nm + 6 + 12 * i;
+ if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)
+ && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {
+ *length = ttUSHORT(fc+loc+8);
+ return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));
+ }
+ }
+ return NULL;
+}
+
+static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)
+{
+ stbtt_int32 i;
+ stbtt_int32 count = ttUSHORT(fc+nm+2);
+ stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);
+
+ for (i=0; i < count; ++i) {
+ stbtt_uint32 loc = nm + 6 + 12 * i;
+ stbtt_int32 id = ttUSHORT(fc+loc+6);
+ if (id == target_id) {
+ // find the encoding
+ stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);
+
+ // is this a Unicode encoding?
+ if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {
+ stbtt_int32 slen = ttUSHORT(fc+loc+8);
+ stbtt_int32 off = ttUSHORT(fc+loc+10);
+
+ // check if there's a prefix match
+ stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);
+ if (matchlen >= 0) {
+ // check for target_id+1 immediately following, with same encoding & language
+ if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {
+ slen = ttUSHORT(fc+loc+12+8);
+ off = ttUSHORT(fc+loc+12+10);
+ if (slen == 0) {
+ if (matchlen == nlen)
+ return 1;
+ } else if (matchlen < nlen && name[matchlen] == ' ') {
+ ++matchlen;
+ if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))
+ return 1;
+ }
+ } else {
+ // if nothing immediately following
+ if (matchlen == nlen)
+ return 1;
+ }
+ }
+ }
+
+ // @TODO handle other encodings
+ }
+ }
+ return 0;
+}
+
+static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)
+{
+ stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);
+ stbtt_uint32 nm,hd;
+ if (!stbtt__isfont(fc+offset)) return 0;
+
+ // check italics/bold/underline flags in macStyle...
+ if (flags) {
+ hd = stbtt__find_table(fc, offset, "head");
+ if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;
+ }
+
+ nm = stbtt__find_table(fc, offset, "name");
+ if (!nm) return 0;
+
+ if (flags) {
+ // if we checked the macStyle flags, then just check the family and ignore the subfamily
+ if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1;
+ if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1;
+ if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1;
+ } else {
+ if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1;
+ if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1;
+ if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1;
+ }
+
+ return 0;
+}
+
+static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags)
+{
+ stbtt_int32 i;
+ for (i=0;;++i) {
+ stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);
+ if (off < 0) return off;
+ if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))
+ return off;
+ }
+}
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+
+STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,
+ float pixel_height, unsigned char *pixels, int pw, int ph,
+ int first_char, int num_chars, stbtt_bakedchar *chardata)
+{
+ return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);
+}
+
+STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)
+{
+ return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);
+}
+
+STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)
+{
+ return stbtt_GetNumberOfFonts_internal((unsigned char *) data);
+}
+
+STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)
+{
+ return stbtt_InitFont_internal(info, (unsigned char *) data, offset);
+}
+
+STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags)
+{
+ return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags);
+}
+
+STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)
+{
+ return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2);
+}
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+#endif // STB_TRUETYPE_IMPLEMENTATION
+
+
+// FULL VERSION HISTORY
+//
+// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
+// 1.11 (2016-04-02) fix unused-variable warning
+// 1.10 (2016-04-02) allow user-defined fabs() replacement
+// fix memory leak if fontsize=0.0
+// fix warning from duplicate typedef
+// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges
+// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
+// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
+// allow PackFontRanges to pack and render in separate phases;
+// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
+// fixed an assert() bug in the new rasterizer
+// replace assert() with STBTT_assert() in new rasterizer
+// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)
+// also more precise AA rasterizer, except if shapes overlap
+// remove need for STBTT_sort
+// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC
+// 1.04 (2015-04-15) typo in example
+// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes
+// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++
+// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match
+// non-oversampled; STBTT_POINT_SIZE for packed case only
+// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling
+// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg)
+// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID
+// 0.8b (2014-07-07) fix a warning
+// 0.8 (2014-05-25) fix a few more warnings
+// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back
+// 0.6c (2012-07-24) improve documentation
+// 0.6b (2012-07-20) fix a few more warnings
+// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels,
+// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty
+// 0.5 (2011-12-09) bugfixes:
+// subpixel glyph renderer computed wrong bounding box
+// first vertex of shape can be off-curve (FreeSans)
+// 0.4b (2011-12-03) fixed an error in the font baking example
+// 0.4 (2011-12-01) kerning, subpixel rendering (tor)
+// bugfixes for:
+// codepoint-to-glyph conversion using table fmt=12
+// codepoint-to-glyph conversion using table fmt=4
+// stbtt_GetBakedQuad with non-square texture (Zer)
+// updated Hello World! sample to use kerning and subpixel
+// fixed some warnings
+// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM)
+// userdata, malloc-from-userdata, non-zero fill (stb)
+// 0.2 (2009-03-11) Fix unsigned/signed char warnings
+// 0.1 (2009-03-09) First public release
+//
diff --git a/src/external/stb_vorbis.c b/src/external/stb_vorbis.c
new file mode 100644
index 00000000..07d79318
--- /dev/null
+++ b/src/external/stb_vorbis.c
@@ -0,0 +1,5010 @@
+#include "stb_vorbis.h"
+
+#ifndef STB_VORBIS_HEADER_ONLY
+
+// global configuration settings (e.g. set these in the project/makefile),
+// or just set them in this file at the top (although ideally the first few
+// should be visible when the header file is compiled too, although it's not
+// crucial)
+
+// STB_VORBIS_NO_PUSHDATA_API
+// does not compile the code for the various stb_vorbis_*_pushdata()
+// functions
+// #define STB_VORBIS_NO_PUSHDATA_API
+
+// STB_VORBIS_NO_PULLDATA_API
+// does not compile the code for the non-pushdata APIs
+// #define STB_VORBIS_NO_PULLDATA_API
+
+// STB_VORBIS_NO_STDIO
+// does not compile the code for the APIs that use FILE *s internally
+// or externally (implied by STB_VORBIS_NO_PULLDATA_API)
+// #define STB_VORBIS_NO_STDIO
+
+// STB_VORBIS_NO_INTEGER_CONVERSION
+// does not compile the code for converting audio sample data from
+// float to integer (implied by STB_VORBIS_NO_PULLDATA_API)
+// #define STB_VORBIS_NO_INTEGER_CONVERSION
+
+// STB_VORBIS_NO_FAST_SCALED_FLOAT
+// does not use a fast float-to-int trick to accelerate float-to-int on
+// most platforms which requires endianness be defined correctly.
+//#define STB_VORBIS_NO_FAST_SCALED_FLOAT
+
+
+// STB_VORBIS_MAX_CHANNELS [number]
+// globally define this to the maximum number of channels you need.
+// The spec does not put a restriction on channels except that
+// the count is stored in a byte, so 255 is the hard limit.
+// Reducing this saves about 16 bytes per value, so using 16 saves
+// (255-16)*16 or around 4KB. Plus anything other memory usage
+// I forgot to account for. Can probably go as low as 8 (7.1 audio),
+// 6 (5.1 audio), or 2 (stereo only).
+#ifndef STB_VORBIS_MAX_CHANNELS
+#define STB_VORBIS_MAX_CHANNELS 16 // enough for anyone?
+#endif
+
+// STB_VORBIS_PUSHDATA_CRC_COUNT [number]
+// after a flush_pushdata(), stb_vorbis begins scanning for the
+// next valid page, without backtracking. when it finds something
+// that looks like a page, it streams through it and verifies its
+// CRC32. Should that validation fail, it keeps scanning. But it's
+// possible that _while_ streaming through to check the CRC32 of
+// one candidate page, it sees another candidate page. This #define
+// determines how many "overlapping" candidate pages it can search
+// at once. Note that "real" pages are typically ~4KB to ~8KB, whereas
+// garbage pages could be as big as 64KB, but probably average ~16KB.
+// So don't hose ourselves by scanning an apparent 64KB page and
+// missing a ton of real ones in the interim; so minimum of 2
+#ifndef STB_VORBIS_PUSHDATA_CRC_COUNT
+#define STB_VORBIS_PUSHDATA_CRC_COUNT 4
+#endif
+
+// STB_VORBIS_FAST_HUFFMAN_LENGTH [number]
+// sets the log size of the huffman-acceleration table. Maximum
+// supported value is 24. with larger numbers, more decodings are O(1),
+// but the table size is larger so worse cache missing, so you'll have
+// to probe (and try multiple ogg vorbis files) to find the sweet spot.
+#ifndef STB_VORBIS_FAST_HUFFMAN_LENGTH
+#define STB_VORBIS_FAST_HUFFMAN_LENGTH 10
+#endif
+
+// STB_VORBIS_FAST_BINARY_LENGTH [number]
+// sets the log size of the binary-search acceleration table. this
+// is used in similar fashion to the fast-huffman size to set initial
+// parameters for the binary search
+
+// STB_VORBIS_FAST_HUFFMAN_INT
+// The fast huffman tables are much more efficient if they can be
+// stored as 16-bit results instead of 32-bit results. This restricts
+// the codebooks to having only 65535 possible outcomes, though.
+// (At least, accelerated by the huffman table.)
+#ifndef STB_VORBIS_FAST_HUFFMAN_INT
+#define STB_VORBIS_FAST_HUFFMAN_SHORT
+#endif
+
+// STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH
+// If the 'fast huffman' search doesn't succeed, then stb_vorbis falls
+// back on binary searching for the correct one. This requires storing
+// extra tables with the huffman codes in sorted order. Defining this
+// symbol trades off space for speed by forcing a linear search in the
+// non-fast case, except for "sparse" codebooks.
+// #define STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH
+
+// STB_VORBIS_DIVIDES_IN_RESIDUE
+// stb_vorbis precomputes the result of the scalar residue decoding
+// that would otherwise require a divide per chunk. you can trade off
+// space for time by defining this symbol.
+// #define STB_VORBIS_DIVIDES_IN_RESIDUE
+
+// STB_VORBIS_DIVIDES_IN_CODEBOOK
+// vorbis VQ codebooks can be encoded two ways: with every case explicitly
+// stored, or with all elements being chosen from a small range of values,
+// and all values possible in all elements. By default, stb_vorbis expands
+// this latter kind out to look like the former kind for ease of decoding,
+// because otherwise an integer divide-per-vector-element is required to
+// unpack the index. If you define STB_VORBIS_DIVIDES_IN_CODEBOOK, you can
+// trade off storage for speed.
+//#define STB_VORBIS_DIVIDES_IN_CODEBOOK
+
+#ifdef STB_VORBIS_CODEBOOK_SHORTS
+#error "STB_VORBIS_CODEBOOK_SHORTS is no longer supported as it produced incorrect results for some input formats"
+#endif
+
+// STB_VORBIS_DIVIDE_TABLE
+// this replaces small integer divides in the floor decode loop with
+// table lookups. made less than 1% difference, so disabled by default.
+
+// STB_VORBIS_NO_INLINE_DECODE
+// disables the inlining of the scalar codebook fast-huffman decode.
+// might save a little codespace; useful for debugging
+// #define STB_VORBIS_NO_INLINE_DECODE
+
+// STB_VORBIS_NO_DEFER_FLOOR
+// Normally we only decode the floor without synthesizing the actual
+// full curve. We can instead synthesize the curve immediately. This
+// requires more memory and is very likely slower, so I don't think
+// you'd ever want to do it except for debugging.
+// #define STB_VORBIS_NO_DEFER_FLOOR
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+#ifdef STB_VORBIS_NO_PULLDATA_API
+ #define STB_VORBIS_NO_INTEGER_CONVERSION
+ #define STB_VORBIS_NO_STDIO
+#endif
+
+#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
+ #define STB_VORBIS_NO_STDIO 1
+#endif
+
+#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
+#ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT
+
+ // only need endianness for fast-float-to-int, which we don't
+ // use for pushdata
+
+ #ifndef STB_VORBIS_BIG_ENDIAN
+ #define STB_VORBIS_ENDIAN 0
+ #else
+ #define STB_VORBIS_ENDIAN 1
+ #endif
+
+#endif
+#endif
+
+
+#ifndef STB_VORBIS_NO_STDIO
+#include <stdio.h>
+#endif
+
+#ifndef STB_VORBIS_NO_CRT
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+#if !(defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh))
+#include <malloc.h>
+#if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__)
+#include <alloca.h>
+#endif
+#endif
+#else // STB_VORBIS_NO_CRT
+#define NULL 0
+#define malloc(s) 0
+#define free(s) ((void) 0)
+#define realloc(s) 0
+#endif // STB_VORBIS_NO_CRT
+
+#include <limits.h>
+
+#ifdef __MINGW32__
+ // eff you mingw:
+ // "fixed":
+ // http://sourceforge.net/p/mingw-w64/mailman/message/32882927/
+ // "no that broke the build, reverted, who cares about C":
+ // http://sourceforge.net/p/mingw-w64/mailman/message/32890381/
+ #ifdef __forceinline
+ #undef __forceinline
+ #endif
+ #define __forceinline
+#elif !defined(_MSC_VER)
+ #if __GNUC__
+ #define __forceinline inline
+ #else
+ #define __forceinline
+ #endif
+#endif
+
+#if STB_VORBIS_MAX_CHANNELS > 256
+#error "Value of STB_VORBIS_MAX_CHANNELS outside of allowed range"
+#endif
+
+#if STB_VORBIS_FAST_HUFFMAN_LENGTH > 24
+#error "Value of STB_VORBIS_FAST_HUFFMAN_LENGTH outside of allowed range"
+#endif
+
+
+#if 0
+#include <crtdbg.h>
+#define CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1])
+#else
+#define CHECK(f) ((void) 0)
+#endif
+
+#define MAX_BLOCKSIZE_LOG 13 // from specification
+#define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG)
+
+
+typedef unsigned char uint8;
+typedef signed char int8;
+typedef unsigned short uint16;
+typedef signed short int16;
+typedef unsigned int uint32;
+typedef signed int int32;
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+typedef float codetype;
+
+// @NOTE
+//
+// Some arrays below are tagged "//varies", which means it's actually
+// a variable-sized piece of data, but rather than malloc I assume it's
+// small enough it's better to just allocate it all together with the
+// main thing
+//
+// Most of the variables are specified with the smallest size I could pack
+// them into. It might give better performance to make them all full-sized
+// integers. It should be safe to freely rearrange the structures or change
+// the sizes larger--nothing relies on silently truncating etc., nor the
+// order of variables.
+
+#define FAST_HUFFMAN_TABLE_SIZE (1 << STB_VORBIS_FAST_HUFFMAN_LENGTH)
+#define FAST_HUFFMAN_TABLE_MASK (FAST_HUFFMAN_TABLE_SIZE - 1)
+
+typedef struct
+{
+ int dimensions, entries;
+ uint8 *codeword_lengths;
+ float minimum_value;
+ float delta_value;
+ uint8 value_bits;
+ uint8 lookup_type;
+ uint8 sequence_p;
+ uint8 sparse;
+ uint32 lookup_values;
+ codetype *multiplicands;
+ uint32 *codewords;
+ #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT
+ int16 fast_huffman[FAST_HUFFMAN_TABLE_SIZE];
+ #else
+ int32 fast_huffman[FAST_HUFFMAN_TABLE_SIZE];
+ #endif
+ uint32 *sorted_codewords;
+ int *sorted_values;
+ int sorted_entries;
+} Codebook;
+
+typedef struct
+{
+ uint8 order;
+ uint16 rate;
+ uint16 bark_map_size;
+ uint8 amplitude_bits;
+ uint8 amplitude_offset;
+ uint8 number_of_books;
+ uint8 book_list[16]; // varies
+} Floor0;
+
+typedef struct
+{
+ uint8 partitions;
+ uint8 partition_class_list[32]; // varies
+ uint8 class_dimensions[16]; // varies
+ uint8 class_subclasses[16]; // varies
+ uint8 class_masterbooks[16]; // varies
+ int16 subclass_books[16][8]; // varies
+ uint16 Xlist[31*8+2]; // varies
+ uint8 sorted_order[31*8+2];
+ uint8 neighbors[31*8+2][2];
+ uint8 floor1_multiplier;
+ uint8 rangebits;
+ int values;
+} Floor1;
+
+typedef union
+{
+ Floor0 floor0;
+ Floor1 floor1;
+} Floor;
+
+typedef struct
+{
+ uint32 begin, end;
+ uint32 part_size;
+ uint8 classifications;
+ uint8 classbook;
+ uint8 **classdata;
+ int16 (*residue_books)[8];
+} Residue;
+
+typedef struct
+{
+ uint8 magnitude;
+ uint8 angle;
+ uint8 mux;
+} MappingChannel;
+
+typedef struct
+{
+ uint16 coupling_steps;
+ MappingChannel *chan;
+ uint8 submaps;
+ uint8 submap_floor[15]; // varies
+ uint8 submap_residue[15]; // varies
+} Mapping;
+
+typedef struct
+{
+ uint8 blockflag;
+ uint8 mapping;
+ uint16 windowtype;
+ uint16 transformtype;
+} Mode;
+
+typedef struct
+{
+ uint32 goal_crc; // expected crc if match
+ int bytes_left; // bytes left in packet
+ uint32 crc_so_far; // running crc
+ int bytes_done; // bytes processed in _current_ chunk
+ uint32 sample_loc; // granule pos encoded in page
+} CRCscan;
+
+typedef struct
+{
+ uint32 page_start, page_end;
+ uint32 last_decoded_sample;
+} ProbedPage;
+
+struct stb_vorbis
+{
+ // user-accessible info
+ unsigned int sample_rate;
+ int channels;
+
+ unsigned int setup_memory_required;
+ unsigned int temp_memory_required;
+ unsigned int setup_temp_memory_required;
+
+ // input config
+#ifndef STB_VORBIS_NO_STDIO
+ FILE *f;
+ uint32 f_start;
+ int close_on_free;
+#endif
+
+ uint8 *stream;
+ uint8 *stream_start;
+ uint8 *stream_end;
+
+ uint32 stream_len;
+
+ uint8 push_mode;
+
+ uint32 first_audio_page_offset;
+
+ ProbedPage p_first, p_last;
+
+ // memory management
+ stb_vorbis_alloc alloc;
+ int setup_offset;
+ int temp_offset;
+
+ // run-time results
+ int eof;
+ enum STBVorbisError error;
+
+ // user-useful data
+
+ // header info
+ int blocksize[2];
+ int blocksize_0, blocksize_1;
+ int codebook_count;
+ Codebook *codebooks;
+ int floor_count;
+ uint16 floor_types[64]; // varies
+ Floor *floor_config;
+ int residue_count;
+ uint16 residue_types[64]; // varies
+ Residue *residue_config;
+ int mapping_count;
+ Mapping *mapping;
+ int mode_count;
+ Mode mode_config[64]; // varies
+
+ uint32 total_samples;
+
+ // decode buffer
+ float *channel_buffers[STB_VORBIS_MAX_CHANNELS];
+ float *outputs [STB_VORBIS_MAX_CHANNELS];
+
+ float *previous_window[STB_VORBIS_MAX_CHANNELS];
+ int previous_length;
+
+ #ifndef STB_VORBIS_NO_DEFER_FLOOR
+ int16 *finalY[STB_VORBIS_MAX_CHANNELS];
+ #else
+ float *floor_buffers[STB_VORBIS_MAX_CHANNELS];
+ #endif
+
+ uint32 current_loc; // sample location of next frame to decode
+ int current_loc_valid;
+
+ // per-blocksize precomputed data
+
+ // twiddle factors
+ float *A[2],*B[2],*C[2];
+ float *window[2];
+ uint16 *bit_reverse[2];
+
+ // current page/packet/segment streaming info
+ uint32 serial; // stream serial number for verification
+ int last_page;
+ int segment_count;
+ uint8 segments[255];
+ uint8 page_flag;
+ uint8 bytes_in_seg;
+ uint8 first_decode;
+ int next_seg;
+ int last_seg; // flag that we're on the last segment
+ int last_seg_which; // what was the segment number of the last seg?
+ uint32 acc;
+ int valid_bits;
+ int packet_bytes;
+ int end_seg_with_known_loc;
+ uint32 known_loc_for_packet;
+ int discard_samples_deferred;
+ uint32 samples_output;
+
+ // push mode scanning
+ int page_crc_tests; // only in push_mode: number of tests active; -1 if not searching
+#ifndef STB_VORBIS_NO_PUSHDATA_API
+ CRCscan scan[STB_VORBIS_PUSHDATA_CRC_COUNT];
+#endif
+
+ // sample-access
+ int channel_buffer_start;
+ int channel_buffer_end;
+};
+
+#if defined(STB_VORBIS_NO_PUSHDATA_API)
+ #define IS_PUSH_MODE(f) FALSE
+#elif defined(STB_VORBIS_NO_PULLDATA_API)
+ #define IS_PUSH_MODE(f) TRUE
+#else
+ #define IS_PUSH_MODE(f) ((f)->push_mode)
+#endif
+
+typedef struct stb_vorbis vorb;
+
+static int error(vorb *f, enum STBVorbisError e)
+{
+ f->error = e;
+ if (!f->eof && e != VORBIS_need_more_data) {
+ f->error=e; // breakpoint for debugging
+ }
+ return 0;
+}
+
+
+// these functions are used for allocating temporary memory
+// while decoding. if you can afford the stack space, use
+// alloca(); otherwise, provide a temp buffer and it will
+// allocate out of those.
+
+#define array_size_required(count,size) (count*(sizeof(void *)+(size)))
+
+#define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size))
+#ifdef dealloca
+#define temp_free(f,p) (f->alloc.alloc_buffer ? 0 : dealloca(size))
+#else
+#define temp_free(f,p) 0
+#endif
+#define temp_alloc_save(f) ((f)->temp_offset)
+#define temp_alloc_restore(f,p) ((f)->temp_offset = (p))
+
+#define temp_block_array(f,count,size) make_block_array(temp_alloc(f,array_size_required(count,size)), count, size)
+
+// given a sufficiently large block of memory, make an array of pointers to subblocks of it
+static void *make_block_array(void *mem, int count, int size)
+{
+ int i;
+ void ** p = (void **) mem;
+ char *q = (char *) (p + count);
+ for (i=0; i < count; ++i) {
+ p[i] = q;
+ q += size;
+ }
+ return p;
+}
+
+static void *setup_malloc(vorb *f, int sz)
+{
+ sz = (sz+3) & ~3;
+ f->setup_memory_required += sz;
+ if (f->alloc.alloc_buffer) {
+ void *p = (char *) f->alloc.alloc_buffer + f->setup_offset;
+ if (f->setup_offset + sz > f->temp_offset) return NULL;
+ f->setup_offset += sz;
+ return p;
+ }
+ return sz ? malloc(sz) : NULL;
+}
+
+static void setup_free(vorb *f, void *p)
+{
+ if (f->alloc.alloc_buffer) return; // do nothing; setup mem is a stack
+ free(p);
+}
+
+static void *setup_temp_malloc(vorb *f, int sz)
+{
+ sz = (sz+3) & ~3;
+ if (f->alloc.alloc_buffer) {
+ if (f->temp_offset - sz < f->setup_offset) return NULL;
+ f->temp_offset -= sz;
+ return (char *) f->alloc.alloc_buffer + f->temp_offset;
+ }
+ return malloc(sz);
+}
+
+static void setup_temp_free(vorb *f, void *p, int sz)
+{
+ if (f->alloc.alloc_buffer) {
+ f->temp_offset += (sz+3)&~3;
+ return;
+ }
+ free(p);
+}
+
+#define CRC32_POLY 0x04c11db7 // from spec
+
+static uint32 crc_table[256];
+static void crc32_init(void)
+{
+ int i,j;
+ uint32 s;
+ for(i=0; i < 256; i++) {
+ for (s=(uint32) i << 24, j=0; j < 8; ++j)
+ s = (s << 1) ^ (s >= (1U<<31) ? CRC32_POLY : 0);
+ crc_table[i] = s;
+ }
+}
+
+static __forceinline uint32 crc32_update(uint32 crc, uint8 byte)
+{
+ return (crc << 8) ^ crc_table[byte ^ (crc >> 24)];
+}
+
+
+// used in setup, and for huffman that doesn't go fast path
+static unsigned int bit_reverse(unsigned int n)
+{
+ n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1);
+ n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2);
+ n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4);
+ n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8);
+ return (n >> 16) | (n << 16);
+}
+
+static float square(float x)
+{
+ return x*x;
+}
+
+// this is a weird definition of log2() for which log2(1) = 1, log2(2) = 2, log2(4) = 3
+// as required by the specification. fast(?) implementation from stb.h
+// @OPTIMIZE: called multiple times per-packet with "constants"; move to setup
+static int ilog(int32 n)
+{
+ static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 };
+
+ // 2 compares if n < 16, 3 compares otherwise (4 if signed or n > 1<<29)
+ if (n < (1 << 14))
+ if (n < (1 << 4)) return 0 + log2_4[n ];
+ else if (n < (1 << 9)) return 5 + log2_4[n >> 5];
+ else return 10 + log2_4[n >> 10];
+ else if (n < (1 << 24))
+ if (n < (1 << 19)) return 15 + log2_4[n >> 15];
+ else return 20 + log2_4[n >> 20];
+ else if (n < (1 << 29)) return 25 + log2_4[n >> 25];
+ else if (n < (1 << 31)) return 30 + log2_4[n >> 30];
+ else return 0; // signed n returns 0
+}
+
+#ifndef M_PI
+ #define M_PI 3.14159265358979323846264f // from CRC
+#endif
+
+// code length assigned to a value with no huffman encoding
+#define NO_CODE 255
+
+/////////////////////// LEAF SETUP FUNCTIONS //////////////////////////
+//
+// these functions are only called at setup, and only a few times
+// per file
+
+static float float32_unpack(uint32 x)
+{
+ // from the specification
+ uint32 mantissa = x & 0x1fffff;
+ uint32 sign = x & 0x80000000;
+ uint32 exp = (x & 0x7fe00000) >> 21;
+ double res = sign ? -(double)mantissa : (double)mantissa;
+ return (float) ldexp((float)res, exp-788);
+}
+
+
+// zlib & jpeg huffman tables assume that the output symbols
+// can either be arbitrarily arranged, or have monotonically
+// increasing frequencies--they rely on the lengths being sorted;
+// this makes for a very simple generation algorithm.
+// vorbis allows a huffman table with non-sorted lengths. This
+// requires a more sophisticated construction, since symbols in
+// order do not map to huffman codes "in order".
+static void add_entry(Codebook *c, uint32 huff_code, int symbol, int count, int len, uint32 *values)
+{
+ if (!c->sparse) {
+ c->codewords [symbol] = huff_code;
+ } else {
+ c->codewords [count] = huff_code;
+ c->codeword_lengths[count] = len;
+ values [count] = symbol;
+ }
+}
+
+static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
+{
+ int i,k,m=0;
+ uint32 available[32];
+
+ memset(available, 0, sizeof(available));
+ // find the first entry
+ for (k=0; k < n; ++k) if (len[k] < NO_CODE) break;
+ if (k == n) { assert(c->sorted_entries == 0); return TRUE; }
+ // add to the list
+ add_entry(c, 0, k, m++, len[k], values);
+ // add all available leaves
+ for (i=1; i <= len[k]; ++i)
+ available[i] = 1U << (32-i);
+ // note that the above code treats the first case specially,
+ // but it's really the same as the following code, so they
+ // could probably be combined (except the initial code is 0,
+ // and I use 0 in available[] to mean 'empty')
+ for (i=k+1; i < n; ++i) {
+ uint32 res;
+ int z = len[i], y;
+ if (z == NO_CODE) continue;
+ // find lowest available leaf (should always be earliest,
+ // which is what the specification calls for)
+ // note that this property, and the fact we can never have
+ // more than one free leaf at a given level, isn't totally
+ // trivial to prove, but it seems true and the assert never
+ // fires, so!
+ while (z > 0 && !available[z]) --z;
+ if (z == 0) { return FALSE; }
+ res = available[z];
+ assert(z >= 0 && z < 32);
+ available[z] = 0;
+ add_entry(c, bit_reverse(res), i, m++, len[i], values);
+ // propogate availability up the tree
+ if (z != len[i]) {
+ assert(len[i] >= 0 && len[i] < 32);
+ for (y=len[i]; y > z; --y) {
+ assert(available[y] == 0);
+ available[y] = res + (1 << (32-y));
+ }
+ }
+ }
+ return TRUE;
+}
+
+// accelerated huffman table allows fast O(1) match of all symbols
+// of length <= STB_VORBIS_FAST_HUFFMAN_LENGTH
+static void compute_accelerated_huffman(Codebook *c)
+{
+ int i, len;
+ for (i=0; i < FAST_HUFFMAN_TABLE_SIZE; ++i)
+ c->fast_huffman[i] = -1;
+
+ len = c->sparse ? c->sorted_entries : c->entries;
+ #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT
+ if (len > 32767) len = 32767; // largest possible value we can encode!
+ #endif
+ for (i=0; i < len; ++i) {
+ if (c->codeword_lengths[i] <= STB_VORBIS_FAST_HUFFMAN_LENGTH) {
+ uint32 z = c->sparse ? bit_reverse(c->sorted_codewords[i]) : c->codewords[i];
+ // set table entries for all bit combinations in the higher bits
+ while (z < FAST_HUFFMAN_TABLE_SIZE) {
+ c->fast_huffman[z] = i;
+ z += 1 << c->codeword_lengths[i];
+ }
+ }
+ }
+}
+
+#ifdef _MSC_VER
+#define STBV_CDECL __cdecl
+#else
+#define STBV_CDECL
+#endif
+
+static int STBV_CDECL uint32_compare(const void *p, const void *q)
+{
+ uint32 x = * (uint32 *) p;
+ uint32 y = * (uint32 *) q;
+ return x < y ? -1 : x > y;
+}
+
+static int include_in_sort(Codebook *c, uint8 len)
+{
+ if (c->sparse) { assert(len != NO_CODE); return TRUE; }
+ if (len == NO_CODE) return FALSE;
+ if (len > STB_VORBIS_FAST_HUFFMAN_LENGTH) return TRUE;
+ return FALSE;
+}
+
+// if the fast table above doesn't work, we want to binary
+// search them... need to reverse the bits
+static void compute_sorted_huffman(Codebook *c, uint8 *lengths, uint32 *values)
+{
+ int i, len;
+ // build a list of all the entries
+ // OPTIMIZATION: don't include the short ones, since they'll be caught by FAST_HUFFMAN.
+ // this is kind of a frivolous optimization--I don't see any performance improvement,
+ // but it's like 4 extra lines of code, so.
+ if (!c->sparse) {
+ int k = 0;
+ for (i=0; i < c->entries; ++i)
+ if (include_in_sort(c, lengths[i]))
+ c->sorted_codewords[k++] = bit_reverse(c->codewords[i]);
+ assert(k == c->sorted_entries);
+ } else {
+ for (i=0; i < c->sorted_entries; ++i)
+ c->sorted_codewords[i] = bit_reverse(c->codewords[i]);
+ }
+
+ qsort(c->sorted_codewords, c->sorted_entries, sizeof(c->sorted_codewords[0]), uint32_compare);
+ c->sorted_codewords[c->sorted_entries] = 0xffffffff;
+
+ len = c->sparse ? c->sorted_entries : c->entries;
+ // now we need to indicate how they correspond; we could either
+ // #1: sort a different data structure that says who they correspond to
+ // #2: for each sorted entry, search the original list to find who corresponds
+ // #3: for each original entry, find the sorted entry
+ // #1 requires extra storage, #2 is slow, #3 can use binary search!
+ for (i=0; i < len; ++i) {
+ int huff_len = c->sparse ? lengths[values[i]] : lengths[i];
+ if (include_in_sort(c,huff_len)) {
+ uint32 code = bit_reverse(c->codewords[i]);
+ int x=0, n=c->sorted_entries;
+ while (n > 1) {
+ // invariant: sc[x] <= code < sc[x+n]
+ int m = x + (n >> 1);
+ if (c->sorted_codewords[m] <= code) {
+ x = m;
+ n -= (n>>1);
+ } else {
+ n >>= 1;
+ }
+ }
+ assert(c->sorted_codewords[x] == code);
+ if (c->sparse) {
+ c->sorted_values[x] = values[i];
+ c->codeword_lengths[x] = huff_len;
+ } else {
+ c->sorted_values[x] = i;
+ }
+ }
+ }
+}
+
+// only run while parsing the header (3 times)
+static int vorbis_validate(uint8 *data)
+{
+ static uint8 vorbis[6] = { 'v', 'o', 'r', 'b', 'i', 's' };
+ return memcmp(data, vorbis, 6) == 0;
+}
+
+// called from setup only, once per code book
+// (formula implied by specification)
+static int lookup1_values(int entries, int dim)
+{
+ int r = (int) floor(exp((float) log((float) entries) / dim));
+ if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning;
+ ++r; // floor() to avoid _ftol() when non-CRT
+ assert(pow((float) r+1, dim) > entries);
+ assert((int) floor(pow((float) r, dim)) <= entries); // (int),floor() as above
+ return r;
+}
+
+// called twice per file
+static void compute_twiddle_factors(int n, float *A, float *B, float *C)
+{
+ int n4 = n >> 2, n8 = n >> 3;
+ int k,k2;
+
+ for (k=k2=0; k < n4; ++k,k2+=2) {
+ A[k2 ] = (float) cos(4*k*M_PI/n);
+ A[k2+1] = (float) -sin(4*k*M_PI/n);
+ B[k2 ] = (float) cos((k2+1)*M_PI/n/2) * 0.5f;
+ B[k2+1] = (float) sin((k2+1)*M_PI/n/2) * 0.5f;
+ }
+ for (k=k2=0; k < n8; ++k,k2+=2) {
+ C[k2 ] = (float) cos(2*(k2+1)*M_PI/n);
+ C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n);
+ }
+}
+
+static void compute_window(int n, float *window)
+{
+ int n2 = n >> 1, i;
+ for (i=0; i < n2; ++i)
+ window[i] = (float) sin(0.5 * M_PI * square((float) sin((i - 0 + 0.5) / n2 * 0.5 * M_PI)));
+}
+
+static void compute_bitreverse(int n, uint16 *rev)
+{
+ int ld = ilog(n) - 1; // ilog is off-by-one from normal definitions
+ int i, n8 = n >> 3;
+ for (i=0; i < n8; ++i)
+ rev[i] = (bit_reverse(i) >> (32-ld+3)) << 2;
+}
+
+static int init_blocksize(vorb *f, int b, int n)
+{
+ int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3;
+ f->A[b] = (float *) setup_malloc(f, sizeof(float) * n2);
+ f->B[b] = (float *) setup_malloc(f, sizeof(float) * n2);
+ f->C[b] = (float *) setup_malloc(f, sizeof(float) * n4);
+ if (!f->A[b] || !f->B[b] || !f->C[b]) return error(f, VORBIS_outofmem);
+ compute_twiddle_factors(n, f->A[b], f->B[b], f->C[b]);
+ f->window[b] = (float *) setup_malloc(f, sizeof(float) * n2);
+ if (!f->window[b]) return error(f, VORBIS_outofmem);
+ compute_window(n, f->window[b]);
+ f->bit_reverse[b] = (uint16 *) setup_malloc(f, sizeof(uint16) * n8);
+ if (!f->bit_reverse[b]) return error(f, VORBIS_outofmem);
+ compute_bitreverse(n, f->bit_reverse[b]);
+ return TRUE;
+}
+
+static void neighbors(uint16 *x, int n, int *plow, int *phigh)
+{
+ int low = -1;
+ int high = 65536;
+ int i;
+ for (i=0; i < n; ++i) {
+ if (x[i] > low && x[i] < x[n]) { *plow = i; low = x[i]; }
+ if (x[i] < high && x[i] > x[n]) { *phigh = i; high = x[i]; }
+ }
+}
+
+// this has been repurposed so y is now the original index instead of y
+typedef struct
+{
+ uint16 x,y;
+} Point;
+
+static int STBV_CDECL point_compare(const void *p, const void *q)
+{
+ Point *a = (Point *) p;
+ Point *b = (Point *) q;
+ return a->x < b->x ? -1 : a->x > b->x;
+}
+
+//
+/////////////////////// END LEAF SETUP FUNCTIONS //////////////////////////
+
+
+#if defined(STB_VORBIS_NO_STDIO)
+ #define USE_MEMORY(z) TRUE
+#else
+ #define USE_MEMORY(z) ((z)->stream)
+#endif
+
+static uint8 get8(vorb *z)
+{
+ if (USE_MEMORY(z)) {
+ if (z->stream >= z->stream_end) { z->eof = TRUE; return 0; }
+ return *z->stream++;
+ }
+
+ #ifndef STB_VORBIS_NO_STDIO
+ {
+ int c = fgetc(z->f);
+ if (c == EOF) { z->eof = TRUE; return 0; }
+ return c;
+ }
+ #endif
+}
+
+static uint32 get32(vorb *f)
+{
+ uint32 x;
+ x = get8(f);
+ x += get8(f) << 8;
+ x += get8(f) << 16;
+ x += (uint32) get8(f) << 24;
+ return x;
+}
+
+static int getn(vorb *z, uint8 *data, int n)
+{
+ if (USE_MEMORY(z)) {
+ if (z->stream+n > z->stream_end) { z->eof = 1; return 0; }
+ memcpy(data, z->stream, n);
+ z->stream += n;
+ return 1;
+ }
+
+ #ifndef STB_VORBIS_NO_STDIO
+ if (fread(data, n, 1, z->f) == 1)
+ return 1;
+ else {
+ z->eof = 1;
+ return 0;
+ }
+ #endif
+}
+
+static void skip(vorb *z, int n)
+{
+ if (USE_MEMORY(z)) {
+ z->stream += n;
+ if (z->stream >= z->stream_end) z->eof = 1;
+ return;
+ }
+ #ifndef STB_VORBIS_NO_STDIO
+ {
+ long x = ftell(z->f);
+ fseek(z->f, x+n, SEEK_SET);
+ }
+ #endif
+}
+
+static int set_file_offset(stb_vorbis *f, unsigned int loc)
+{
+ #ifndef STB_VORBIS_NO_PUSHDATA_API
+ if (f->push_mode) return 0;
+ #endif
+ f->eof = 0;
+ if (USE_MEMORY(f)) {
+ if (f->stream_start + loc >= f->stream_end || f->stream_start + loc < f->stream_start) {
+ f->stream = f->stream_end;
+ f->eof = 1;
+ return 0;
+ } else {
+ f->stream = f->stream_start + loc;
+ return 1;
+ }
+ }
+ #ifndef STB_VORBIS_NO_STDIO
+ if (loc + f->f_start < loc || loc >= 0x80000000) {
+ loc = 0x7fffffff;
+ f->eof = 1;
+ } else {
+ loc += f->f_start;
+ }
+ if (!fseek(f->f, loc, SEEK_SET))
+ return 1;
+ f->eof = 1;
+ fseek(f->f, f->f_start, SEEK_END);
+ return 0;
+ #endif
+}
+
+
+static uint8 ogg_page_header[4] = { 0x4f, 0x67, 0x67, 0x53 };
+
+static int capture_pattern(vorb *f)
+{
+ if (0x4f != get8(f)) return FALSE;
+ if (0x67 != get8(f)) return FALSE;
+ if (0x67 != get8(f)) return FALSE;
+ if (0x53 != get8(f)) return FALSE;
+ return TRUE;
+}
+
+#define PAGEFLAG_continued_packet 1
+#define PAGEFLAG_first_page 2
+#define PAGEFLAG_last_page 4
+
+static int start_page_no_capturepattern(vorb *f)
+{
+ uint32 loc0,loc1,n;
+ // stream structure version
+ if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version);
+ // header flag
+ f->page_flag = get8(f);
+ // absolute granule position
+ loc0 = get32(f);
+ loc1 = get32(f);
+ // @TODO: validate loc0,loc1 as valid positions?
+ // stream serial number -- vorbis doesn't interleave, so discard
+ get32(f);
+ //if (f->serial != get32(f)) return error(f, VORBIS_incorrect_stream_serial_number);
+ // page sequence number
+ n = get32(f);
+ f->last_page = n;
+ // CRC32
+ get32(f);
+ // page_segments
+ f->segment_count = get8(f);
+ if (!getn(f, f->segments, f->segment_count))
+ return error(f, VORBIS_unexpected_eof);
+ // assume we _don't_ know any the sample position of any segments
+ f->end_seg_with_known_loc = -2;
+ if (loc0 != ~0U || loc1 != ~0U) {
+ int i;
+ // determine which packet is the last one that will complete
+ for (i=f->segment_count-1; i >= 0; --i)
+ if (f->segments[i] < 255)
+ break;
+ // 'i' is now the index of the _last_ segment of a packet that ends
+ if (i >= 0) {
+ f->end_seg_with_known_loc = i;
+ f->known_loc_for_packet = loc0;
+ }
+ }
+ if (f->first_decode) {
+ int i,len;
+ ProbedPage p;
+ len = 0;
+ for (i=0; i < f->segment_count; ++i)
+ len += f->segments[i];
+ len += 27 + f->segment_count;
+ p.page_start = f->first_audio_page_offset;
+ p.page_end = p.page_start + len;
+ p.last_decoded_sample = loc0;
+ f->p_first = p;
+ }
+ f->next_seg = 0;
+ return TRUE;
+}
+
+static int start_page(vorb *f)
+{
+ if (!capture_pattern(f)) return error(f, VORBIS_missing_capture_pattern);
+ return start_page_no_capturepattern(f);
+}
+
+static int start_packet(vorb *f)
+{
+ while (f->next_seg == -1) {
+ if (!start_page(f)) return FALSE;
+ if (f->page_flag & PAGEFLAG_continued_packet)
+ return error(f, VORBIS_continued_packet_flag_invalid);
+ }
+ f->last_seg = FALSE;
+ f->valid_bits = 0;
+ f->packet_bytes = 0;
+ f->bytes_in_seg = 0;
+ // f->next_seg is now valid
+ return TRUE;
+}
+
+static int maybe_start_packet(vorb *f)
+{
+ if (f->next_seg == -1) {
+ int x = get8(f);
+ if (f->eof) return FALSE; // EOF at page boundary is not an error!
+ if (0x4f != x ) return error(f, VORBIS_missing_capture_pattern);
+ if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern);
+ if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern);
+ if (0x53 != get8(f)) return error(f, VORBIS_missing_capture_pattern);
+ if (!start_page_no_capturepattern(f)) return FALSE;
+ if (f->page_flag & PAGEFLAG_continued_packet) {
+ // set up enough state that we can read this packet if we want,
+ // e.g. during recovery
+ f->last_seg = FALSE;
+ f->bytes_in_seg = 0;
+ return error(f, VORBIS_continued_packet_flag_invalid);
+ }
+ }
+ return start_packet(f);
+}
+
+static int next_segment(vorb *f)
+{
+ int len;
+ if (f->last_seg) return 0;
+ if (f->next_seg == -1) {
+ f->last_seg_which = f->segment_count-1; // in case start_page fails
+ if (!start_page(f)) { f->last_seg = 1; return 0; }
+ if (!(f->page_flag & PAGEFLAG_continued_packet)) return error(f, VORBIS_continued_packet_flag_invalid);
+ }
+ len = f->segments[f->next_seg++];
+ if (len < 255) {
+ f->last_seg = TRUE;
+ f->last_seg_which = f->next_seg-1;
+ }
+ if (f->next_seg >= f->segment_count)
+ f->next_seg = -1;
+ assert(f->bytes_in_seg == 0);
+ f->bytes_in_seg = len;
+ return len;
+}
+
+#define EOP (-1)
+#define INVALID_BITS (-1)
+
+static int get8_packet_raw(vorb *f)
+{
+ if (!f->bytes_in_seg) { // CLANG!
+ if (f->last_seg) return EOP;
+ else if (!next_segment(f)) return EOP;
+ }
+ assert(f->bytes_in_seg > 0);
+ --f->bytes_in_seg;
+ ++f->packet_bytes;
+ return get8(f);
+}
+
+static int get8_packet(vorb *f)
+{
+ int x = get8_packet_raw(f);
+ f->valid_bits = 0;
+ return x;
+}
+
+static void flush_packet(vorb *f)
+{
+ while (get8_packet_raw(f) != EOP);
+}
+
+// @OPTIMIZE: this is the secondary bit decoder, so it's probably not as important
+// as the huffman decoder?
+static uint32 get_bits(vorb *f, int n)
+{
+ uint32 z;
+
+ if (f->valid_bits < 0) return 0;
+ if (f->valid_bits < n) {
+ if (n > 24) {
+ // the accumulator technique below would not work correctly in this case
+ z = get_bits(f, 24);
+ z += get_bits(f, n-24) << 24;
+ return z;
+ }
+ if (f->valid_bits == 0) f->acc = 0;
+ while (f->valid_bits < n) {
+ int z = get8_packet_raw(f);
+ if (z == EOP) {
+ f->valid_bits = INVALID_BITS;
+ return 0;
+ }
+ f->acc += z << f->valid_bits;
+ f->valid_bits += 8;
+ }
+ }
+ if (f->valid_bits < 0) return 0;
+ z = f->acc & ((1 << n)-1);
+ f->acc >>= n;
+ f->valid_bits -= n;
+ return z;
+}
+
+// @OPTIMIZE: primary accumulator for huffman
+// expand the buffer to as many bits as possible without reading off end of packet
+// it might be nice to allow f->valid_bits and f->acc to be stored in registers,
+// e.g. cache them locally and decode locally
+static __forceinline void prep_huffman(vorb *f)
+{
+ if (f->valid_bits <= 24) {
+ if (f->valid_bits == 0) f->acc = 0;
+ do {
+ int z;
+ if (f->last_seg && !f->bytes_in_seg) return;
+ z = get8_packet_raw(f);
+ if (z == EOP) return;
+ f->acc += (unsigned) z << f->valid_bits;
+ f->valid_bits += 8;
+ } while (f->valid_bits <= 24);
+ }
+}
+
+enum
+{
+ VORBIS_packet_id = 1,
+ VORBIS_packet_comment = 3,
+ VORBIS_packet_setup = 5
+};
+
+static int codebook_decode_scalar_raw(vorb *f, Codebook *c)
+{
+ int i;
+ prep_huffman(f);
+
+ if (c->codewords == NULL && c->sorted_codewords == NULL)
+ return -1;
+
+ // cases to use binary search: sorted_codewords && !c->codewords
+ // sorted_codewords && c->entries > 8
+ if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) {
+ // binary search
+ uint32 code = bit_reverse(f->acc);
+ int x=0, n=c->sorted_entries, len;
+
+ while (n > 1) {
+ // invariant: sc[x] <= code < sc[x+n]
+ int m = x + (n >> 1);
+ if (c->sorted_codewords[m] <= code) {
+ x = m;
+ n -= (n>>1);
+ } else {
+ n >>= 1;
+ }
+ }
+ // x is now the sorted index
+ if (!c->sparse) x = c->sorted_values[x];
+ // x is now sorted index if sparse, or symbol otherwise
+ len = c->codeword_lengths[x];
+ if (f->valid_bits >= len) {
+ f->acc >>= len;
+ f->valid_bits -= len;
+ return x;
+ }
+
+ f->valid_bits = 0;
+ return -1;
+ }
+
+ // if small, linear search
+ assert(!c->sparse);
+ for (i=0; i < c->entries; ++i) {
+ if (c->codeword_lengths[i] == NO_CODE) continue;
+ if (c->codewords[i] == (f->acc & ((1 << c->codeword_lengths[i])-1))) {
+ if (f->valid_bits >= c->codeword_lengths[i]) {
+ f->acc >>= c->codeword_lengths[i];
+ f->valid_bits -= c->codeword_lengths[i];
+ return i;
+ }
+ f->valid_bits = 0;
+ return -1;
+ }
+ }
+
+ error(f, VORBIS_invalid_stream);
+ f->valid_bits = 0;
+ return -1;
+}
+
+#ifndef STB_VORBIS_NO_INLINE_DECODE
+
+#define DECODE_RAW(var, f,c) \
+ if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH) \
+ prep_huffman(f); \
+ var = f->acc & FAST_HUFFMAN_TABLE_MASK; \
+ var = c->fast_huffman[var]; \
+ if (var >= 0) { \
+ int n = c->codeword_lengths[var]; \
+ f->acc >>= n; \
+ f->valid_bits -= n; \
+ if (f->valid_bits < 0) { f->valid_bits = 0; var = -1; } \
+ } else { \
+ var = codebook_decode_scalar_raw(f,c); \
+ }
+
+#else
+
+static int codebook_decode_scalar(vorb *f, Codebook *c)
+{
+ int i;
+ if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH)
+ prep_huffman(f);
+ // fast huffman table lookup
+ i = f->acc & FAST_HUFFMAN_TABLE_MASK;
+ i = c->fast_huffman[i];
+ if (i >= 0) {
+ f->acc >>= c->codeword_lengths[i];
+ f->valid_bits -= c->codeword_lengths[i];
+ if (f->valid_bits < 0) { f->valid_bits = 0; return -1; }
+ return i;
+ }
+ return codebook_decode_scalar_raw(f,c);
+}
+
+#define DECODE_RAW(var,f,c) var = codebook_decode_scalar(f,c);
+
+#endif
+
+#define DECODE(var,f,c) \
+ DECODE_RAW(var,f,c) \
+ if (c->sparse) var = c->sorted_values[var];
+
+#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ #define DECODE_VQ(var,f,c) DECODE_RAW(var,f,c)
+#else
+ #define DECODE_VQ(var,f,c) DECODE(var,f,c)
+#endif
+
+
+
+
+
+
+// CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case
+// where we avoid one addition
+#define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off])
+#define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off])
+#define CODEBOOK_ELEMENT_BASE(c) (0)
+
+static int codebook_decode_start(vorb *f, Codebook *c)
+{
+ int z = -1;
+
+ // type 0 is only legal in a scalar context
+ if (c->lookup_type == 0)
+ error(f, VORBIS_invalid_stream);
+ else {
+ DECODE_VQ(z,f,c);
+ if (c->sparse) assert(z < c->sorted_entries);
+ if (z < 0) { // check for EOP
+ if (!f->bytes_in_seg)
+ if (f->last_seg)
+ return z;
+ error(f, VORBIS_invalid_stream);
+ }
+ }
+ return z;
+}
+
+static int codebook_decode(vorb *f, Codebook *c, float *output, int len)
+{
+ int i,z = codebook_decode_start(f,c);
+ if (z < 0) return FALSE;
+ if (len > c->dimensions) len = c->dimensions;
+
+#ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ if (c->lookup_type == 1) {
+ float last = CODEBOOK_ELEMENT_BASE(c);
+ int div = 1;
+ for (i=0; i < len; ++i) {
+ int off = (z / div) % c->lookup_values;
+ float val = CODEBOOK_ELEMENT_FAST(c,off) + last;
+ output[i] += val;
+ if (c->sequence_p) last = val + c->minimum_value;
+ div *= c->lookup_values;
+ }
+ return TRUE;
+ }
+#endif
+
+ z *= c->dimensions;
+ if (c->sequence_p) {
+ float last = CODEBOOK_ELEMENT_BASE(c);
+ for (i=0; i < len; ++i) {
+ float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
+ output[i] += val;
+ last = val + c->minimum_value;
+ }
+ } else {
+ float last = CODEBOOK_ELEMENT_BASE(c);
+ for (i=0; i < len; ++i) {
+ output[i] += CODEBOOK_ELEMENT_FAST(c,z+i) + last;
+ }
+ }
+
+ return TRUE;
+}
+
+static int codebook_decode_step(vorb *f, Codebook *c, float *output, int len, int step)
+{
+ int i,z = codebook_decode_start(f,c);
+ float last = CODEBOOK_ELEMENT_BASE(c);
+ if (z < 0) return FALSE;
+ if (len > c->dimensions) len = c->dimensions;
+
+#ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ if (c->lookup_type == 1) {
+ int div = 1;
+ for (i=0; i < len; ++i) {
+ int off = (z / div) % c->lookup_values;
+ float val = CODEBOOK_ELEMENT_FAST(c,off) + last;
+ output[i*step] += val;
+ if (c->sequence_p) last = val;
+ div *= c->lookup_values;
+ }
+ return TRUE;
+ }
+#endif
+
+ z *= c->dimensions;
+ for (i=0; i < len; ++i) {
+ float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
+ output[i*step] += val;
+ if (c->sequence_p) last = val;
+ }
+
+ return TRUE;
+}
+
+static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **outputs, int ch, int *c_inter_p, int *p_inter_p, int len, int total_decode)
+{
+ int c_inter = *c_inter_p;
+ int p_inter = *p_inter_p;
+ int i,z, effective = c->dimensions;
+
+ // type 0 is only legal in a scalar context
+ if (c->lookup_type == 0) return error(f, VORBIS_invalid_stream);
+
+ while (total_decode > 0) {
+ float last = CODEBOOK_ELEMENT_BASE(c);
+ DECODE_VQ(z,f,c);
+ #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ assert(!c->sparse || z < c->sorted_entries);
+ #endif
+ if (z < 0) {
+ if (!f->bytes_in_seg)
+ if (f->last_seg) return FALSE;
+ return error(f, VORBIS_invalid_stream);
+ }
+
+ // if this will take us off the end of the buffers, stop short!
+ // we check by computing the length of the virtual interleaved
+ // buffer (len*ch), our current offset within it (p_inter*ch)+(c_inter),
+ // and the length we'll be using (effective)
+ if (c_inter + p_inter*ch + effective > len * ch) {
+ effective = len*ch - (p_inter*ch - c_inter);
+ }
+
+ #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ if (c->lookup_type == 1) {
+ int div = 1;
+ for (i=0; i < effective; ++i) {
+ int off = (z / div) % c->lookup_values;
+ float val = CODEBOOK_ELEMENT_FAST(c,off) + last;
+ if (outputs[c_inter])
+ outputs[c_inter][p_inter] += val;
+ if (++c_inter == ch) { c_inter = 0; ++p_inter; }
+ if (c->sequence_p) last = val;
+ div *= c->lookup_values;
+ }
+ } else
+ #endif
+ {
+ z *= c->dimensions;
+ if (c->sequence_p) {
+ for (i=0; i < effective; ++i) {
+ float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
+ if (outputs[c_inter])
+ outputs[c_inter][p_inter] += val;
+ if (++c_inter == ch) { c_inter = 0; ++p_inter; }
+ last = val;
+ }
+ } else {
+ for (i=0; i < effective; ++i) {
+ float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
+ if (outputs[c_inter])
+ outputs[c_inter][p_inter] += val;
+ if (++c_inter == ch) { c_inter = 0; ++p_inter; }
+ }
+ }
+ }
+
+ total_decode -= effective;
+ }
+ *c_inter_p = c_inter;
+ *p_inter_p = p_inter;
+ return TRUE;
+}
+
+static int predict_point(int x, int x0, int x1, int y0, int y1)
+{
+ int dy = y1 - y0;
+ int adx = x1 - x0;
+ // @OPTIMIZE: force int division to round in the right direction... is this necessary on x86?
+ int err = abs(dy) * (x - x0);
+ int off = err / adx;
+ return dy < 0 ? y0 - off : y0 + off;
+}
+
+// the following table is block-copied from the specification
+static float inverse_db_table[256] =
+{
+ 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f,
+ 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f,
+ 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.1287530e-07f,
+ 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f,
+ 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f,
+ 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f,
+ 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f,
+ 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f,
+ 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f,
+ 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f,
+ 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f,
+ 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f,
+ 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f,
+ 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f,
+ 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f,
+ 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f,
+ 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f,
+ 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f,
+ 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f,
+ 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f,
+ 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f,
+ 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f,
+ 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f,
+ 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f,
+ 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f,
+ 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f,
+ 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f,
+ 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f,
+ 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f,
+ 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f,
+ 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f,
+ 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f,
+ 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f,
+ 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f,
+ 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f,
+ 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f,
+ 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f,
+ 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f,
+ 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f,
+ 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f,
+ 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f,
+ 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f,
+ 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f,
+ 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f,
+ 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f,
+ 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f,
+ 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f,
+ 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f,
+ 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f,
+ 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f,
+ 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f,
+ 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f,
+ 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f,
+ 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f,
+ 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f,
+ 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f,
+ 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f,
+ 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f,
+ 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f,
+ 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f,
+ 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f,
+ 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f,
+ 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f,
+ 0.82788260f, 0.88168307f, 0.9389798f, 1.0f
+};
+
+
+// @OPTIMIZE: if you want to replace this bresenham line-drawing routine,
+// note that you must produce bit-identical output to decode correctly;
+// this specific sequence of operations is specified in the spec (it's
+// drawing integer-quantized frequency-space lines that the encoder
+// expects to be exactly the same)
+// ... also, isn't the whole point of Bresenham's algorithm to NOT
+// have to divide in the setup? sigh.
+#ifndef STB_VORBIS_NO_DEFER_FLOOR
+#define LINE_OP(a,b) a *= b
+#else
+#define LINE_OP(a,b) a = b
+#endif
+
+#ifdef STB_VORBIS_DIVIDE_TABLE
+#define DIVTAB_NUMER 32
+#define DIVTAB_DENOM 64
+int8 integer_divide_table[DIVTAB_NUMER][DIVTAB_DENOM]; // 2KB
+#endif
+
+static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y1, int n)
+{
+ int dy = y1 - y0;
+ int adx = x1 - x0;
+ int ady = abs(dy);
+ int base;
+ int x=x0,y=y0;
+ int err = 0;
+ int sy;
+
+#ifdef STB_VORBIS_DIVIDE_TABLE
+ if (adx < DIVTAB_DENOM && ady < DIVTAB_NUMER) {
+ if (dy < 0) {
+ base = -integer_divide_table[ady][adx];
+ sy = base-1;
+ } else {
+ base = integer_divide_table[ady][adx];
+ sy = base+1;
+ }
+ } else {
+ base = dy / adx;
+ if (dy < 0)
+ sy = base - 1;
+ else
+ sy = base+1;
+ }
+#else
+ base = dy / adx;
+ if (dy < 0)
+ sy = base - 1;
+ else
+ sy = base+1;
+#endif
+ ady -= abs(base) * adx;
+ if (x1 > n) x1 = n;
+ if (x < x1) {
+ LINE_OP(output[x], inverse_db_table[y]);
+ for (++x; x < x1; ++x) {
+ err += ady;
+ if (err >= adx) {
+ err -= adx;
+ y += sy;
+ } else
+ y += base;
+ LINE_OP(output[x], inverse_db_table[y]);
+ }
+ }
+}
+
+static int residue_decode(vorb *f, Codebook *book, float *target, int offset, int n, int rtype)
+{
+ int k;
+ if (rtype == 0) {
+ int step = n / book->dimensions;
+ for (k=0; k < step; ++k)
+ if (!codebook_decode_step(f, book, target+offset+k, n-offset-k, step))
+ return FALSE;
+ } else {
+ for (k=0; k < n; ) {
+ if (!codebook_decode(f, book, target+offset, n-k))
+ return FALSE;
+ k += book->dimensions;
+ offset += book->dimensions;
+ }
+ }
+ return TRUE;
+}
+
+static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode)
+{
+ int i,j,pass;
+ Residue *r = f->residue_config + rn;
+ int rtype = f->residue_types[rn];
+ int c = r->classbook;
+ int classwords = f->codebooks[c].dimensions;
+ int n_read = r->end - r->begin;
+ int part_read = n_read / r->part_size;
+ int temp_alloc_point = temp_alloc_save(f);
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ uint8 ***part_classdata = (uint8 ***) temp_block_array(f,f->channels, part_read * sizeof(**part_classdata));
+ #else
+ int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications));
+ #endif
+
+ CHECK(f);
+
+ for (i=0; i < ch; ++i)
+ if (!do_not_decode[i])
+ memset(residue_buffers[i], 0, sizeof(float) * n);
+
+ if (rtype == 2 && ch != 1) {
+ for (j=0; j < ch; ++j)
+ if (!do_not_decode[j])
+ break;
+ if (j == ch)
+ goto done;
+
+ for (pass=0; pass < 8; ++pass) {
+ int pcount = 0, class_set = 0;
+ if (ch == 2) {
+ while (pcount < part_read) {
+ int z = r->begin + pcount*r->part_size;
+ int c_inter = (z & 1), p_inter = z>>1;
+ if (pass == 0) {
+ Codebook *c = f->codebooks+r->classbook;
+ int q;
+ DECODE(q,f,c);
+ if (q == EOP) goto done;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ part_classdata[0][class_set] = r->classdata[q];
+ #else
+ for (i=classwords-1; i >= 0; --i) {
+ classifications[0][i+pcount] = q % r->classifications;
+ q /= r->classifications;
+ }
+ #endif
+ }
+ for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
+ int z = r->begin + pcount*r->part_size;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ int c = part_classdata[0][class_set][i];
+ #else
+ int c = classifications[0][pcount];
+ #endif
+ int b = r->residue_books[c][pass];
+ if (b >= 0) {
+ Codebook *book = f->codebooks + b;
+ #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
+ goto done;
+ #else
+ // saves 1%
+ if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
+ goto done;
+ #endif
+ } else {
+ z += r->part_size;
+ c_inter = z & 1;
+ p_inter = z >> 1;
+ }
+ }
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ ++class_set;
+ #endif
+ }
+ } else if (ch == 1) {
+ while (pcount < part_read) {
+ int z = r->begin + pcount*r->part_size;
+ int c_inter = 0, p_inter = z;
+ if (pass == 0) {
+ Codebook *c = f->codebooks+r->classbook;
+ int q;
+ DECODE(q,f,c);
+ if (q == EOP) goto done;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ part_classdata[0][class_set] = r->classdata[q];
+ #else
+ for (i=classwords-1; i >= 0; --i) {
+ classifications[0][i+pcount] = q % r->classifications;
+ q /= r->classifications;
+ }
+ #endif
+ }
+ for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
+ int z = r->begin + pcount*r->part_size;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ int c = part_classdata[0][class_set][i];
+ #else
+ int c = classifications[0][pcount];
+ #endif
+ int b = r->residue_books[c][pass];
+ if (b >= 0) {
+ Codebook *book = f->codebooks + b;
+ if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
+ goto done;
+ } else {
+ z += r->part_size;
+ c_inter = 0;
+ p_inter = z;
+ }
+ }
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ ++class_set;
+ #endif
+ }
+ } else {
+ while (pcount < part_read) {
+ int z = r->begin + pcount*r->part_size;
+ int c_inter = z % ch, p_inter = z/ch;
+ if (pass == 0) {
+ Codebook *c = f->codebooks+r->classbook;
+ int q;
+ DECODE(q,f,c);
+ if (q == EOP) goto done;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ part_classdata[0][class_set] = r->classdata[q];
+ #else
+ for (i=classwords-1; i >= 0; --i) {
+ classifications[0][i+pcount] = q % r->classifications;
+ q /= r->classifications;
+ }
+ #endif
+ }
+ for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
+ int z = r->begin + pcount*r->part_size;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ int c = part_classdata[0][class_set][i];
+ #else
+ int c = classifications[0][pcount];
+ #endif
+ int b = r->residue_books[c][pass];
+ if (b >= 0) {
+ Codebook *book = f->codebooks + b;
+ if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
+ goto done;
+ } else {
+ z += r->part_size;
+ c_inter = z % ch;
+ p_inter = z / ch;
+ }
+ }
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ ++class_set;
+ #endif
+ }
+ }
+ }
+ goto done;
+ }
+ CHECK(f);
+
+ for (pass=0; pass < 8; ++pass) {
+ int pcount = 0, class_set=0;
+ while (pcount < part_read) {
+ if (pass == 0) {
+ for (j=0; j < ch; ++j) {
+ if (!do_not_decode[j]) {
+ Codebook *c = f->codebooks+r->classbook;
+ int temp;
+ DECODE(temp,f,c);
+ if (temp == EOP) goto done;
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ part_classdata[j][class_set] = r->classdata[temp];
+ #else
+ for (i=classwords-1; i >= 0; --i) {
+ classifications[j][i+pcount] = temp % r->classifications;
+ temp /= r->classifications;
+ }
+ #endif
+ }
+ }
+ }
+ for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
+ for (j=0; j < ch; ++j) {
+ if (!do_not_decode[j]) {
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ int c = part_classdata[j][class_set][i];
+ #else
+ int c = classifications[j][pcount];
+ #endif
+ int b = r->residue_books[c][pass];
+ if (b >= 0) {
+ float *target = residue_buffers[j];
+ int offset = r->begin + pcount * r->part_size;
+ int n = r->part_size;
+ Codebook *book = f->codebooks + b;
+ if (!residue_decode(f, book, target, offset, n, rtype))
+ goto done;
+ }
+ }
+ }
+ }
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ ++class_set;
+ #endif
+ }
+ }
+ done:
+ CHECK(f);
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ temp_free(f,part_classdata);
+ #else
+ temp_free(f,classifications);
+ #endif
+ temp_alloc_restore(f,temp_alloc_point);
+}
+
+
+#if 0
+// slow way for debugging
+void inverse_mdct_slow(float *buffer, int n)
+{
+ int i,j;
+ int n2 = n >> 1;
+ float *x = (float *) malloc(sizeof(*x) * n2);
+ memcpy(x, buffer, sizeof(*x) * n2);
+ for (i=0; i < n; ++i) {
+ float acc = 0;
+ for (j=0; j < n2; ++j)
+ // formula from paper:
+ //acc += n/4.0f * x[j] * (float) cos(M_PI / 2 / n * (2 * i + 1 + n/2.0)*(2*j+1));
+ // formula from wikipedia
+ //acc += 2.0f / n2 * x[j] * (float) cos(M_PI/n2 * (i + 0.5 + n2/2)*(j + 0.5));
+ // these are equivalent, except the formula from the paper inverts the multiplier!
+ // however, what actually works is NO MULTIPLIER!?!
+ //acc += 64 * 2.0f / n2 * x[j] * (float) cos(M_PI/n2 * (i + 0.5 + n2/2)*(j + 0.5));
+ acc += x[j] * (float) cos(M_PI / 2 / n * (2 * i + 1 + n/2.0)*(2*j+1));
+ buffer[i] = acc;
+ }
+ free(x);
+}
+#elif 0
+// same as above, but just barely able to run in real time on modern machines
+void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype)
+{
+ float mcos[16384];
+ int i,j;
+ int n2 = n >> 1, nmask = (n << 2) -1;
+ float *x = (float *) malloc(sizeof(*x) * n2);
+ memcpy(x, buffer, sizeof(*x) * n2);
+ for (i=0; i < 4*n; ++i)
+ mcos[i] = (float) cos(M_PI / 2 * i / n);
+
+ for (i=0; i < n; ++i) {
+ float acc = 0;
+ for (j=0; j < n2; ++j)
+ acc += x[j] * mcos[(2 * i + 1 + n2)*(2*j+1) & nmask];
+ buffer[i] = acc;
+ }
+ free(x);
+}
+#elif 0
+// transform to use a slow dct-iv; this is STILL basically trivial,
+// but only requires half as many ops
+void dct_iv_slow(float *buffer, int n)
+{
+ float mcos[16384];
+ float x[2048];
+ int i,j;
+ int n2 = n >> 1, nmask = (n << 3) - 1;
+ memcpy(x, buffer, sizeof(*x) * n);
+ for (i=0; i < 8*n; ++i)
+ mcos[i] = (float) cos(M_PI / 4 * i / n);
+ for (i=0; i < n; ++i) {
+ float acc = 0;
+ for (j=0; j < n; ++j)
+ acc += x[j] * mcos[((2 * i + 1)*(2*j+1)) & nmask];
+ buffer[i] = acc;
+ }
+}
+
+void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype)
+{
+ int i, n4 = n >> 2, n2 = n >> 1, n3_4 = n - n4;
+ float temp[4096];
+
+ memcpy(temp, buffer, n2 * sizeof(float));
+ dct_iv_slow(temp, n2); // returns -c'-d, a-b'
+
+ for (i=0; i < n4 ; ++i) buffer[i] = temp[i+n4]; // a-b'
+ for ( ; i < n3_4; ++i) buffer[i] = -temp[n3_4 - i - 1]; // b-a', c+d'
+ for ( ; i < n ; ++i) buffer[i] = -temp[i - n3_4]; // c'+d
+}
+#endif
+
+#ifndef LIBVORBIS_MDCT
+#define LIBVORBIS_MDCT 0
+#endif
+
+#if LIBVORBIS_MDCT
+// directly call the vorbis MDCT using an interface documented
+// by Jeff Roberts... useful for performance comparison
+typedef struct
+{
+ int n;
+ int log2n;
+
+ float *trig;
+ int *bitrev;
+
+ float scale;
+} mdct_lookup;
+
+extern void mdct_init(mdct_lookup *lookup, int n);
+extern void mdct_clear(mdct_lookup *l);
+extern void mdct_backward(mdct_lookup *init, float *in, float *out);
+
+mdct_lookup M1,M2;
+
+void inverse_mdct(float *buffer, int n, vorb *f, int blocktype)
+{
+ mdct_lookup *M;
+ if (M1.n == n) M = &M1;
+ else if (M2.n == n) M = &M2;
+ else if (M1.n == 0) { mdct_init(&M1, n); M = &M1; }
+ else {
+ if (M2.n) __asm int 3;
+ mdct_init(&M2, n);
+ M = &M2;
+ }
+
+ mdct_backward(M, buffer, buffer);
+}
+#endif
+
+
+// the following were split out into separate functions while optimizing;
+// they could be pushed back up but eh. __forceinline showed no change;
+// they're probably already being inlined.
+static void imdct_step3_iter0_loop(int n, float *e, int i_off, int k_off, float *A)
+{
+ float *ee0 = e + i_off;
+ float *ee2 = ee0 + k_off;
+ int i;
+
+ assert((n & 3) == 0);
+ for (i=(n>>2); i > 0; --i) {
+ float k00_20, k01_21;
+ k00_20 = ee0[ 0] - ee2[ 0];
+ k01_21 = ee0[-1] - ee2[-1];
+ ee0[ 0] += ee2[ 0];//ee0[ 0] = ee0[ 0] + ee2[ 0];
+ ee0[-1] += ee2[-1];//ee0[-1] = ee0[-1] + ee2[-1];
+ ee2[ 0] = k00_20 * A[0] - k01_21 * A[1];
+ ee2[-1] = k01_21 * A[0] + k00_20 * A[1];
+ A += 8;
+
+ k00_20 = ee0[-2] - ee2[-2];
+ k01_21 = ee0[-3] - ee2[-3];
+ ee0[-2] += ee2[-2];//ee0[-2] = ee0[-2] + ee2[-2];
+ ee0[-3] += ee2[-3];//ee0[-3] = ee0[-3] + ee2[-3];
+ ee2[-2] = k00_20 * A[0] - k01_21 * A[1];
+ ee2[-3] = k01_21 * A[0] + k00_20 * A[1];
+ A += 8;
+
+ k00_20 = ee0[-4] - ee2[-4];
+ k01_21 = ee0[-5] - ee2[-5];
+ ee0[-4] += ee2[-4];//ee0[-4] = ee0[-4] + ee2[-4];
+ ee0[-5] += ee2[-5];//ee0[-5] = ee0[-5] + ee2[-5];
+ ee2[-4] = k00_20 * A[0] - k01_21 * A[1];
+ ee2[-5] = k01_21 * A[0] + k00_20 * A[1];
+ A += 8;
+
+ k00_20 = ee0[-6] - ee2[-6];
+ k01_21 = ee0[-7] - ee2[-7];
+ ee0[-6] += ee2[-6];//ee0[-6] = ee0[-6] + ee2[-6];
+ ee0[-7] += ee2[-7];//ee0[-7] = ee0[-7] + ee2[-7];
+ ee2[-6] = k00_20 * A[0] - k01_21 * A[1];
+ ee2[-7] = k01_21 * A[0] + k00_20 * A[1];
+ A += 8;
+ ee0 -= 8;
+ ee2 -= 8;
+ }
+}
+
+static void imdct_step3_inner_r_loop(int lim, float *e, int d0, int k_off, float *A, int k1)
+{
+ int i;
+ float k00_20, k01_21;
+
+ float *e0 = e + d0;
+ float *e2 = e0 + k_off;
+
+ for (i=lim >> 2; i > 0; --i) {
+ k00_20 = e0[-0] - e2[-0];
+ k01_21 = e0[-1] - e2[-1];
+ e0[-0] += e2[-0];//e0[-0] = e0[-0] + e2[-0];
+ e0[-1] += e2[-1];//e0[-1] = e0[-1] + e2[-1];
+ e2[-0] = (k00_20)*A[0] - (k01_21) * A[1];
+ e2[-1] = (k01_21)*A[0] + (k00_20) * A[1];
+
+ A += k1;
+
+ k00_20 = e0[-2] - e2[-2];
+ k01_21 = e0[-3] - e2[-3];
+ e0[-2] += e2[-2];//e0[-2] = e0[-2] + e2[-2];
+ e0[-3] += e2[-3];//e0[-3] = e0[-3] + e2[-3];
+ e2[-2] = (k00_20)*A[0] - (k01_21) * A[1];
+ e2[-3] = (k01_21)*A[0] + (k00_20) * A[1];
+
+ A += k1;
+
+ k00_20 = e0[-4] - e2[-4];
+ k01_21 = e0[-5] - e2[-5];
+ e0[-4] += e2[-4];//e0[-4] = e0[-4] + e2[-4];
+ e0[-5] += e2[-5];//e0[-5] = e0[-5] + e2[-5];
+ e2[-4] = (k00_20)*A[0] - (k01_21) * A[1];
+ e2[-5] = (k01_21)*A[0] + (k00_20) * A[1];
+
+ A += k1;
+
+ k00_20 = e0[-6] - e2[-6];
+ k01_21 = e0[-7] - e2[-7];
+ e0[-6] += e2[-6];//e0[-6] = e0[-6] + e2[-6];
+ e0[-7] += e2[-7];//e0[-7] = e0[-7] + e2[-7];
+ e2[-6] = (k00_20)*A[0] - (k01_21) * A[1];
+ e2[-7] = (k01_21)*A[0] + (k00_20) * A[1];
+
+ e0 -= 8;
+ e2 -= 8;
+
+ A += k1;
+ }
+}
+
+static void imdct_step3_inner_s_loop(int n, float *e, int i_off, int k_off, float *A, int a_off, int k0)
+{
+ int i;
+ float A0 = A[0];
+ float A1 = A[0+1];
+ float A2 = A[0+a_off];
+ float A3 = A[0+a_off+1];
+ float A4 = A[0+a_off*2+0];
+ float A5 = A[0+a_off*2+1];
+ float A6 = A[0+a_off*3+0];
+ float A7 = A[0+a_off*3+1];
+
+ float k00,k11;
+
+ float *ee0 = e +i_off;
+ float *ee2 = ee0+k_off;
+
+ for (i=n; i > 0; --i) {
+ k00 = ee0[ 0] - ee2[ 0];
+ k11 = ee0[-1] - ee2[-1];
+ ee0[ 0] = ee0[ 0] + ee2[ 0];
+ ee0[-1] = ee0[-1] + ee2[-1];
+ ee2[ 0] = (k00) * A0 - (k11) * A1;
+ ee2[-1] = (k11) * A0 + (k00) * A1;
+
+ k00 = ee0[-2] - ee2[-2];
+ k11 = ee0[-3] - ee2[-3];
+ ee0[-2] = ee0[-2] + ee2[-2];
+ ee0[-3] = ee0[-3] + ee2[-3];
+ ee2[-2] = (k00) * A2 - (k11) * A3;
+ ee2[-3] = (k11) * A2 + (k00) * A3;
+
+ k00 = ee0[-4] - ee2[-4];
+ k11 = ee0[-5] - ee2[-5];
+ ee0[-4] = ee0[-4] + ee2[-4];
+ ee0[-5] = ee0[-5] + ee2[-5];
+ ee2[-4] = (k00) * A4 - (k11) * A5;
+ ee2[-5] = (k11) * A4 + (k00) * A5;
+
+ k00 = ee0[-6] - ee2[-6];
+ k11 = ee0[-7] - ee2[-7];
+ ee0[-6] = ee0[-6] + ee2[-6];
+ ee0[-7] = ee0[-7] + ee2[-7];
+ ee2[-6] = (k00) * A6 - (k11) * A7;
+ ee2[-7] = (k11) * A6 + (k00) * A7;
+
+ ee0 -= k0;
+ ee2 -= k0;
+ }
+}
+
+static __forceinline void iter_54(float *z)
+{
+ float k00,k11,k22,k33;
+ float y0,y1,y2,y3;
+
+ k00 = z[ 0] - z[-4];
+ y0 = z[ 0] + z[-4];
+ y2 = z[-2] + z[-6];
+ k22 = z[-2] - z[-6];
+
+ z[-0] = y0 + y2; // z0 + z4 + z2 + z6
+ z[-2] = y0 - y2; // z0 + z4 - z2 - z6
+
+ // done with y0,y2
+
+ k33 = z[-3] - z[-7];
+
+ z[-4] = k00 + k33; // z0 - z4 + z3 - z7
+ z[-6] = k00 - k33; // z0 - z4 - z3 + z7
+
+ // done with k33
+
+ k11 = z[-1] - z[-5];
+ y1 = z[-1] + z[-5];
+ y3 = z[-3] + z[-7];
+
+ z[-1] = y1 + y3; // z1 + z5 + z3 + z7
+ z[-3] = y1 - y3; // z1 + z5 - z3 - z7
+ z[-5] = k11 - k22; // z1 - z5 + z2 - z6
+ z[-7] = k11 + k22; // z1 - z5 - z2 + z6
+}
+
+static void imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A, int base_n)
+{
+ int a_off = base_n >> 3;
+ float A2 = A[0+a_off];
+ float *z = e + i_off;
+ float *base = z - 16 * n;
+
+ while (z > base) {
+ float k00,k11;
+
+ k00 = z[-0] - z[-8];
+ k11 = z[-1] - z[-9];
+ z[-0] = z[-0] + z[-8];
+ z[-1] = z[-1] + z[-9];
+ z[-8] = k00;
+ z[-9] = k11 ;
+
+ k00 = z[ -2] - z[-10];
+ k11 = z[ -3] - z[-11];
+ z[ -2] = z[ -2] + z[-10];
+ z[ -3] = z[ -3] + z[-11];
+ z[-10] = (k00+k11) * A2;
+ z[-11] = (k11-k00) * A2;
+
+ k00 = z[-12] - z[ -4]; // reverse to avoid a unary negation
+ k11 = z[ -5] - z[-13];
+ z[ -4] = z[ -4] + z[-12];
+ z[ -5] = z[ -5] + z[-13];
+ z[-12] = k11;
+ z[-13] = k00;
+
+ k00 = z[-14] - z[ -6]; // reverse to avoid a unary negation
+ k11 = z[ -7] - z[-15];
+ z[ -6] = z[ -6] + z[-14];
+ z[ -7] = z[ -7] + z[-15];
+ z[-14] = (k00+k11) * A2;
+ z[-15] = (k00-k11) * A2;
+
+ iter_54(z);
+ iter_54(z-8);
+ z -= 16;
+ }
+}
+
+static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype)
+{
+ int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l;
+ int ld;
+ // @OPTIMIZE: reduce register pressure by using fewer variables?
+ int save_point = temp_alloc_save(f);
+ float *buf2 = (float *) temp_alloc(f, n2 * sizeof(*buf2));
+ float *u=NULL,*v=NULL;
+ // twiddle factors
+ float *A = f->A[blocktype];
+
+ // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio"
+ // See notes about bugs in that paper in less-optimal implementation 'inverse_mdct_old' after this function.
+
+ // kernel from paper
+
+
+ // merged:
+ // copy and reflect spectral data
+ // step 0
+
+ // note that it turns out that the items added together during
+ // this step are, in fact, being added to themselves (as reflected
+ // by step 0). inexplicable inefficiency! this became obvious
+ // once I combined the passes.
+
+ // so there's a missing 'times 2' here (for adding X to itself).
+ // this propogates through linearly to the end, where the numbers
+ // are 1/2 too small, and need to be compensated for.
+
+ {
+ float *d,*e, *AA, *e_stop;
+ d = &buf2[n2-2];
+ AA = A;
+ e = &buffer[0];
+ e_stop = &buffer[n2];
+ while (e != e_stop) {
+ d[1] = (e[0] * AA[0] - e[2]*AA[1]);
+ d[0] = (e[0] * AA[1] + e[2]*AA[0]);
+ d -= 2;
+ AA += 2;
+ e += 4;
+ }
+
+ e = &buffer[n2-3];
+ while (d >= buf2) {
+ d[1] = (-e[2] * AA[0] - -e[0]*AA[1]);
+ d[0] = (-e[2] * AA[1] + -e[0]*AA[0]);
+ d -= 2;
+ AA += 2;
+ e -= 4;
+ }
+ }
+
+ // now we use symbolic names for these, so that we can
+ // possibly swap their meaning as we change which operations
+ // are in place
+
+ u = buffer;
+ v = buf2;
+
+ // step 2 (paper output is w, now u)
+ // this could be in place, but the data ends up in the wrong
+ // place... _somebody_'s got to swap it, so this is nominated
+ {
+ float *AA = &A[n2-8];
+ float *d0,*d1, *e0, *e1;
+
+ e0 = &v[n4];
+ e1 = &v[0];
+
+ d0 = &u[n4];
+ d1 = &u[0];
+
+ while (AA >= A) {
+ float v40_20, v41_21;
+
+ v41_21 = e0[1] - e1[1];
+ v40_20 = e0[0] - e1[0];
+ d0[1] = e0[1] + e1[1];
+ d0[0] = e0[0] + e1[0];
+ d1[1] = v41_21*AA[4] - v40_20*AA[5];
+ d1[0] = v40_20*AA[4] + v41_21*AA[5];
+
+ v41_21 = e0[3] - e1[3];
+ v40_20 = e0[2] - e1[2];
+ d0[3] = e0[3] + e1[3];
+ d0[2] = e0[2] + e1[2];
+ d1[3] = v41_21*AA[0] - v40_20*AA[1];
+ d1[2] = v40_20*AA[0] + v41_21*AA[1];
+
+ AA -= 8;
+
+ d0 += 4;
+ d1 += 4;
+ e0 += 4;
+ e1 += 4;
+ }
+ }
+
+ // step 3
+ ld = ilog(n) - 1; // ilog is off-by-one from normal definitions
+
+ // optimized step 3:
+
+ // the original step3 loop can be nested r inside s or s inside r;
+ // it's written originally as s inside r, but this is dumb when r
+ // iterates many times, and s few. So I have two copies of it and
+ // switch between them halfway.
+
+ // this is iteration 0 of step 3
+ imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*0, -(n >> 3), A);
+ imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*1, -(n >> 3), A);
+
+ // this is iteration 1 of step 3
+ imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*0, -(n >> 4), A, 16);
+ imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*1, -(n >> 4), A, 16);
+ imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*2, -(n >> 4), A, 16);
+ imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*3, -(n >> 4), A, 16);
+
+ l=2;
+ for (; l < (ld-3)>>1; ++l) {
+ int k0 = n >> (l+2), k0_2 = k0>>1;
+ int lim = 1 << (l+1);
+ int i;
+ for (i=0; i < lim; ++i)
+ imdct_step3_inner_r_loop(n >> (l+4), u, n2-1 - k0*i, -k0_2, A, 1 << (l+3));
+ }
+
+ for (; l < ld-6; ++l) {
+ int k0 = n >> (l+2), k1 = 1 << (l+3), k0_2 = k0>>1;
+ int rlim = n >> (l+6), r;
+ int lim = 1 << (l+1);
+ int i_off;
+ float *A0 = A;
+ i_off = n2-1;
+ for (r=rlim; r > 0; --r) {
+ imdct_step3_inner_s_loop(lim, u, i_off, -k0_2, A0, k1, k0);
+ A0 += k1*4;
+ i_off -= 8;
+ }
+ }
+
+ // iterations with count:
+ // ld-6,-5,-4 all interleaved together
+ // the big win comes from getting rid of needless flops
+ // due to the constants on pass 5 & 4 being all 1 and 0;
+ // combining them to be simultaneous to improve cache made little difference
+ imdct_step3_inner_s_loop_ld654(n >> 5, u, n2-1, A, n);
+
+ // output is u
+
+ // step 4, 5, and 6
+ // cannot be in-place because of step 5
+ {
+ uint16 *bitrev = f->bit_reverse[blocktype];
+ // weirdly, I'd have thought reading sequentially and writing
+ // erratically would have been better than vice-versa, but in
+ // fact that's not what my testing showed. (That is, with
+ // j = bitreverse(i), do you read i and write j, or read j and write i.)
+
+ float *d0 = &v[n4-4];
+ float *d1 = &v[n2-4];
+ while (d0 >= v) {
+ int k4;
+
+ k4 = bitrev[0];
+ d1[3] = u[k4+0];
+ d1[2] = u[k4+1];
+ d0[3] = u[k4+2];
+ d0[2] = u[k4+3];
+
+ k4 = bitrev[1];
+ d1[1] = u[k4+0];
+ d1[0] = u[k4+1];
+ d0[1] = u[k4+2];
+ d0[0] = u[k4+3];
+
+ d0 -= 4;
+ d1 -= 4;
+ bitrev += 2;
+ }
+ }
+ // (paper output is u, now v)
+
+
+ // data must be in buf2
+ assert(v == buf2);
+
+ // step 7 (paper output is v, now v)
+ // this is now in place
+ {
+ float *C = f->C[blocktype];
+ float *d, *e;
+
+ d = v;
+ e = v + n2 - 4;
+
+ while (d < e) {
+ float a02,a11,b0,b1,b2,b3;
+
+ a02 = d[0] - e[2];
+ a11 = d[1] + e[3];
+
+ b0 = C[1]*a02 + C[0]*a11;
+ b1 = C[1]*a11 - C[0]*a02;
+
+ b2 = d[0] + e[ 2];
+ b3 = d[1] - e[ 3];
+
+ d[0] = b2 + b0;
+ d[1] = b3 + b1;
+ e[2] = b2 - b0;
+ e[3] = b1 - b3;
+
+ a02 = d[2] - e[0];
+ a11 = d[3] + e[1];
+
+ b0 = C[3]*a02 + C[2]*a11;
+ b1 = C[3]*a11 - C[2]*a02;
+
+ b2 = d[2] + e[ 0];
+ b3 = d[3] - e[ 1];
+
+ d[2] = b2 + b0;
+ d[3] = b3 + b1;
+ e[0] = b2 - b0;
+ e[1] = b1 - b3;
+
+ C += 4;
+ d += 4;
+ e -= 4;
+ }
+ }
+
+ // data must be in buf2
+
+
+ // step 8+decode (paper output is X, now buffer)
+ // this generates pairs of data a la 8 and pushes them directly through
+ // the decode kernel (pushing rather than pulling) to avoid having
+ // to make another pass later
+
+ // this cannot POSSIBLY be in place, so we refer to the buffers directly
+
+ {
+ float *d0,*d1,*d2,*d3;
+
+ float *B = f->B[blocktype] + n2 - 8;
+ float *e = buf2 + n2 - 8;
+ d0 = &buffer[0];
+ d1 = &buffer[n2-4];
+ d2 = &buffer[n2];
+ d3 = &buffer[n-4];
+ while (e >= v) {
+ float p0,p1,p2,p3;
+
+ p3 = e[6]*B[7] - e[7]*B[6];
+ p2 = -e[6]*B[6] - e[7]*B[7];
+
+ d0[0] = p3;
+ d1[3] = - p3;
+ d2[0] = p2;
+ d3[3] = p2;
+
+ p1 = e[4]*B[5] - e[5]*B[4];
+ p0 = -e[4]*B[4] - e[5]*B[5];
+
+ d0[1] = p1;
+ d1[2] = - p1;
+ d2[1] = p0;
+ d3[2] = p0;
+
+ p3 = e[2]*B[3] - e[3]*B[2];
+ p2 = -e[2]*B[2] - e[3]*B[3];
+
+ d0[2] = p3;
+ d1[1] = - p3;
+ d2[2] = p2;
+ d3[1] = p2;
+
+ p1 = e[0]*B[1] - e[1]*B[0];
+ p0 = -e[0]*B[0] - e[1]*B[1];
+
+ d0[3] = p1;
+ d1[0] = - p1;
+ d2[3] = p0;
+ d3[0] = p0;
+
+ B -= 8;
+ e -= 8;
+ d0 += 4;
+ d2 += 4;
+ d1 -= 4;
+ d3 -= 4;
+ }
+ }
+
+ temp_free(f,buf2);
+ temp_alloc_restore(f,save_point);
+}
+
+#if 0
+// this is the original version of the above code, if you want to optimize it from scratch
+void inverse_mdct_naive(float *buffer, int n)
+{
+ float s;
+ float A[1 << 12], B[1 << 12], C[1 << 11];
+ int i,k,k2,k4, n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l;
+ int n3_4 = n - n4, ld;
+ // how can they claim this only uses N words?!
+ // oh, because they're only used sparsely, whoops
+ float u[1 << 13], X[1 << 13], v[1 << 13], w[1 << 13];
+ // set up twiddle factors
+
+ for (k=k2=0; k < n4; ++k,k2+=2) {
+ A[k2 ] = (float) cos(4*k*M_PI/n);
+ A[k2+1] = (float) -sin(4*k*M_PI/n);
+ B[k2 ] = (float) cos((k2+1)*M_PI/n/2);
+ B[k2+1] = (float) sin((k2+1)*M_PI/n/2);
+ }
+ for (k=k2=0; k < n8; ++k,k2+=2) {
+ C[k2 ] = (float) cos(2*(k2+1)*M_PI/n);
+ C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n);
+ }
+
+ // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio"
+ // Note there are bugs in that pseudocode, presumably due to them attempting
+ // to rename the arrays nicely rather than representing the way their actual
+ // implementation bounces buffers back and forth. As a result, even in the
+ // "some formulars corrected" version, a direct implementation fails. These
+ // are noted below as "paper bug".
+
+ // copy and reflect spectral data
+ for (k=0; k < n2; ++k) u[k] = buffer[k];
+ for ( ; k < n ; ++k) u[k] = -buffer[n - k - 1];
+ // kernel from paper
+ // step 1
+ for (k=k2=k4=0; k < n4; k+=1, k2+=2, k4+=4) {
+ v[n-k4-1] = (u[k4] - u[n-k4-1]) * A[k2] - (u[k4+2] - u[n-k4-3])*A[k2+1];
+ v[n-k4-3] = (u[k4] - u[n-k4-1]) * A[k2+1] + (u[k4+2] - u[n-k4-3])*A[k2];
+ }
+ // step 2
+ for (k=k4=0; k < n8; k+=1, k4+=4) {
+ w[n2+3+k4] = v[n2+3+k4] + v[k4+3];
+ w[n2+1+k4] = v[n2+1+k4] + v[k4+1];
+ w[k4+3] = (v[n2+3+k4] - v[k4+3])*A[n2-4-k4] - (v[n2+1+k4]-v[k4+1])*A[n2-3-k4];
+ w[k4+1] = (v[n2+1+k4] - v[k4+1])*A[n2-4-k4] + (v[n2+3+k4]-v[k4+3])*A[n2-3-k4];
+ }
+ // step 3
+ ld = ilog(n) - 1; // ilog is off-by-one from normal definitions
+ for (l=0; l < ld-3; ++l) {
+ int k0 = n >> (l+2), k1 = 1 << (l+3);
+ int rlim = n >> (l+4), r4, r;
+ int s2lim = 1 << (l+2), s2;
+ for (r=r4=0; r < rlim; r4+=4,++r) {
+ for (s2=0; s2 < s2lim; s2+=2) {
+ u[n-1-k0*s2-r4] = w[n-1-k0*s2-r4] + w[n-1-k0*(s2+1)-r4];
+ u[n-3-k0*s2-r4] = w[n-3-k0*s2-r4] + w[n-3-k0*(s2+1)-r4];
+ u[n-1-k0*(s2+1)-r4] = (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1]
+ - (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1+1];
+ u[n-3-k0*(s2+1)-r4] = (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1]
+ + (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1+1];
+ }
+ }
+ if (l+1 < ld-3) {
+ // paper bug: ping-ponging of u&w here is omitted
+ memcpy(w, u, sizeof(u));
+ }
+ }
+
+ // step 4
+ for (i=0; i < n8; ++i) {
+ int j = bit_reverse(i) >> (32-ld+3);
+ assert(j < n8);
+ if (i == j) {
+ // paper bug: original code probably swapped in place; if copying,
+ // need to directly copy in this case
+ int i8 = i << 3;
+ v[i8+1] = u[i8+1];
+ v[i8+3] = u[i8+3];
+ v[i8+5] = u[i8+5];
+ v[i8+7] = u[i8+7];
+ } else if (i < j) {
+ int i8 = i << 3, j8 = j << 3;
+ v[j8+1] = u[i8+1], v[i8+1] = u[j8 + 1];
+ v[j8+3] = u[i8+3], v[i8+3] = u[j8 + 3];
+ v[j8+5] = u[i8+5], v[i8+5] = u[j8 + 5];
+ v[j8+7] = u[i8+7], v[i8+7] = u[j8 + 7];
+ }
+ }
+ // step 5
+ for (k=0; k < n2; ++k) {
+ w[k] = v[k*2+1];
+ }
+ // step 6
+ for (k=k2=k4=0; k < n8; ++k, k2 += 2, k4 += 4) {
+ u[n-1-k2] = w[k4];
+ u[n-2-k2] = w[k4+1];
+ u[n3_4 - 1 - k2] = w[k4+2];
+ u[n3_4 - 2 - k2] = w[k4+3];
+ }
+ // step 7
+ for (k=k2=0; k < n8; ++k, k2 += 2) {
+ v[n2 + k2 ] = ( u[n2 + k2] + u[n-2-k2] + C[k2+1]*(u[n2+k2]-u[n-2-k2]) + C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2;
+ v[n-2 - k2] = ( u[n2 + k2] + u[n-2-k2] - C[k2+1]*(u[n2+k2]-u[n-2-k2]) - C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2;
+ v[n2+1+ k2] = ( u[n2+1+k2] - u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2;
+ v[n-1 - k2] = (-u[n2+1+k2] + u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2;
+ }
+ // step 8
+ for (k=k2=0; k < n4; ++k,k2 += 2) {
+ X[k] = v[k2+n2]*B[k2 ] + v[k2+1+n2]*B[k2+1];
+ X[n2-1-k] = v[k2+n2]*B[k2+1] - v[k2+1+n2]*B[k2 ];
+ }
+
+ // decode kernel to output
+ // determined the following value experimentally
+ // (by first figuring out what made inverse_mdct_slow work); then matching that here
+ // (probably vorbis encoder premultiplies by n or n/2, to save it on the decoder?)
+ s = 0.5; // theoretically would be n4
+
+ // [[[ note! the s value of 0.5 is compensated for by the B[] in the current code,
+ // so it needs to use the "old" B values to behave correctly, or else
+ // set s to 1.0 ]]]
+ for (i=0; i < n4 ; ++i) buffer[i] = s * X[i+n4];
+ for ( ; i < n3_4; ++i) buffer[i] = -s * X[n3_4 - i - 1];
+ for ( ; i < n ; ++i) buffer[i] = -s * X[i - n3_4];
+}
+#endif
+
+static float *get_window(vorb *f, int len)
+{
+ len <<= 1;
+ if (len == f->blocksize_0) return f->window[0];
+ if (len == f->blocksize_1) return f->window[1];
+ assert(0);
+ return NULL;
+}
+
+#ifndef STB_VORBIS_NO_DEFER_FLOOR
+typedef int16 YTYPE;
+#else
+typedef int YTYPE;
+#endif
+static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *finalY, uint8 *step2_flag)
+{
+ int n2 = n >> 1;
+ int s = map->chan[i].mux, floor;
+ floor = map->submap_floor[s];
+ if (f->floor_types[floor] == 0) {
+ return error(f, VORBIS_invalid_stream);
+ } else {
+ Floor1 *g = &f->floor_config[floor].floor1;
+ int j,q;
+ int lx = 0, ly = finalY[0] * g->floor1_multiplier;
+ for (q=1; q < g->values; ++q) {
+ j = g->sorted_order[q];
+ #ifndef STB_VORBIS_NO_DEFER_FLOOR
+ if (finalY[j] >= 0)
+ #else
+ if (step2_flag[j])
+ #endif
+ {
+ int hy = finalY[j] * g->floor1_multiplier;
+ int hx = g->Xlist[j];
+ if (lx != hx)
+ draw_line(target, lx,ly, hx,hy, n2);
+ CHECK(f);
+ lx = hx, ly = hy;
+ }
+ }
+ if (lx < n2) {
+ // optimization of: draw_line(target, lx,ly, n,ly, n2);
+ for (j=lx; j < n2; ++j)
+ LINE_OP(target[j], inverse_db_table[ly]);
+ CHECK(f);
+ }
+ }
+ return TRUE;
+}
+
+// The meaning of "left" and "right"
+//
+// For a given frame:
+// we compute samples from 0..n
+// window_center is n/2
+// we'll window and mix the samples from left_start to left_end with data from the previous frame
+// all of the samples from left_end to right_start can be output without mixing; however,
+// this interval is 0-length except when transitioning between short and long frames
+// all of the samples from right_start to right_end need to be mixed with the next frame,
+// which we don't have, so those get saved in a buffer
+// frame N's right_end-right_start, the number of samples to mix with the next frame,
+// has to be the same as frame N+1's left_end-left_start (which they are by
+// construction)
+
+static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode)
+{
+ Mode *m;
+ int i, n, prev, next, window_center;
+ f->channel_buffer_start = f->channel_buffer_end = 0;
+
+ retry:
+ if (f->eof) return FALSE;
+ if (!maybe_start_packet(f))
+ return FALSE;
+ // check packet type
+ if (get_bits(f,1) != 0) {
+ if (IS_PUSH_MODE(f))
+ return error(f,VORBIS_bad_packet_type);
+ while (EOP != get8_packet(f));
+ goto retry;
+ }
+
+ if (f->alloc.alloc_buffer)
+ assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
+
+ i = get_bits(f, ilog(f->mode_count-1));
+ if (i == EOP) return FALSE;
+ if (i >= f->mode_count) return FALSE;
+ *mode = i;
+ m = f->mode_config + i;
+ if (m->blockflag) {
+ n = f->blocksize_1;
+ prev = get_bits(f,1);
+ next = get_bits(f,1);
+ } else {
+ prev = next = 0;
+ n = f->blocksize_0;
+ }
+
+// WINDOWING
+
+ window_center = n >> 1;
+ if (m->blockflag && !prev) {
+ *p_left_start = (n - f->blocksize_0) >> 2;
+ *p_left_end = (n + f->blocksize_0) >> 2;
+ } else {
+ *p_left_start = 0;
+ *p_left_end = window_center;
+ }
+ if (m->blockflag && !next) {
+ *p_right_start = (n*3 - f->blocksize_0) >> 2;
+ *p_right_end = (n*3 + f->blocksize_0) >> 2;
+ } else {
+ *p_right_start = window_center;
+ *p_right_end = n;
+ }
+
+ return TRUE;
+}
+
+static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, int left_end, int right_start, int right_end, int *p_left)
+{
+ Mapping *map;
+ int i,j,k,n,n2;
+ int zero_channel[256];
+ int really_zero_channel[256];
+
+// WINDOWING
+
+ n = f->blocksize[m->blockflag];
+ map = &f->mapping[m->mapping];
+
+// FLOORS
+ n2 = n >> 1;
+
+ CHECK(f);
+
+ for (i=0; i < f->channels; ++i) {
+ int s = map->chan[i].mux, floor;
+ zero_channel[i] = FALSE;
+ floor = map->submap_floor[s];
+ if (f->floor_types[floor] == 0) {
+ return error(f, VORBIS_invalid_stream);
+ } else {
+ Floor1 *g = &f->floor_config[floor].floor1;
+ if (get_bits(f, 1)) {
+ short *finalY;
+ uint8 step2_flag[256];
+ static int range_list[4] = { 256, 128, 86, 64 };
+ int range = range_list[g->floor1_multiplier-1];
+ int offset = 2;
+ finalY = f->finalY[i];
+ finalY[0] = get_bits(f, ilog(range)-1);
+ finalY[1] = get_bits(f, ilog(range)-1);
+ for (j=0; j < g->partitions; ++j) {
+ int pclass = g->partition_class_list[j];
+ int cdim = g->class_dimensions[pclass];
+ int cbits = g->class_subclasses[pclass];
+ int csub = (1 << cbits)-1;
+ int cval = 0;
+ if (cbits) {
+ Codebook *c = f->codebooks + g->class_masterbooks[pclass];
+ DECODE(cval,f,c);
+ }
+ for (k=0; k < cdim; ++k) {
+ int book = g->subclass_books[pclass][cval & csub];
+ cval = cval >> cbits;
+ if (book >= 0) {
+ int temp;
+ Codebook *c = f->codebooks + book;
+ DECODE(temp,f,c);
+ finalY[offset++] = temp;
+ } else
+ finalY[offset++] = 0;
+ }
+ }
+ if (f->valid_bits == INVALID_BITS) goto error; // behavior according to spec
+ step2_flag[0] = step2_flag[1] = 1;
+ for (j=2; j < g->values; ++j) {
+ int low, high, pred, highroom, lowroom, room, val;
+ low = g->neighbors[j][0];
+ high = g->neighbors[j][1];
+ //neighbors(g->Xlist, j, &low, &high);
+ pred = predict_point(g->Xlist[j], g->Xlist[low], g->Xlist[high], finalY[low], finalY[high]);
+ val = finalY[j];
+ highroom = range - pred;
+ lowroom = pred;
+ if (highroom < lowroom)
+ room = highroom * 2;
+ else
+ room = lowroom * 2;
+ if (val) {
+ step2_flag[low] = step2_flag[high] = 1;
+ step2_flag[j] = 1;
+ if (val >= room)
+ if (highroom > lowroom)
+ finalY[j] = val - lowroom + pred;
+ else
+ finalY[j] = pred - val + highroom - 1;
+ else
+ if (val & 1)
+ finalY[j] = pred - ((val+1)>>1);
+ else
+ finalY[j] = pred + (val>>1);
+ } else {
+ step2_flag[j] = 0;
+ finalY[j] = pred;
+ }
+ }
+
+#ifdef STB_VORBIS_NO_DEFER_FLOOR
+ do_floor(f, map, i, n, f->floor_buffers[i], finalY, step2_flag);
+#else
+ // defer final floor computation until _after_ residue
+ for (j=0; j < g->values; ++j) {
+ if (!step2_flag[j])
+ finalY[j] = -1;
+ }
+#endif
+ } else {
+ error:
+ zero_channel[i] = TRUE;
+ }
+ // So we just defer everything else to later
+
+ // at this point we've decoded the floor into buffer
+ }
+ }
+ CHECK(f);
+ // at this point we've decoded all floors
+
+ if (f->alloc.alloc_buffer)
+ assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
+
+ // re-enable coupled channels if necessary
+ memcpy(really_zero_channel, zero_channel, sizeof(really_zero_channel[0]) * f->channels);
+ for (i=0; i < map->coupling_steps; ++i)
+ if (!zero_channel[map->chan[i].magnitude] || !zero_channel[map->chan[i].angle]) {
+ zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE;
+ }
+
+ CHECK(f);
+// RESIDUE DECODE
+ for (i=0; i < map->submaps; ++i) {
+ float *residue_buffers[STB_VORBIS_MAX_CHANNELS];
+ int r;
+ uint8 do_not_decode[256];
+ int ch = 0;
+ for (j=0; j < f->channels; ++j) {
+ if (map->chan[j].mux == i) {
+ if (zero_channel[j]) {
+ do_not_decode[ch] = TRUE;
+ residue_buffers[ch] = NULL;
+ } else {
+ do_not_decode[ch] = FALSE;
+ residue_buffers[ch] = f->channel_buffers[j];
+ }
+ ++ch;
+ }
+ }
+ r = map->submap_residue[i];
+ decode_residue(f, residue_buffers, ch, n2, r, do_not_decode);
+ }
+
+ if (f->alloc.alloc_buffer)
+ assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
+ CHECK(f);
+
+// INVERSE COUPLING
+ for (i = map->coupling_steps-1; i >= 0; --i) {
+ int n2 = n >> 1;
+ float *m = f->channel_buffers[map->chan[i].magnitude];
+ float *a = f->channel_buffers[map->chan[i].angle ];
+ for (j=0; j < n2; ++j) {
+ float a2,m2;
+ if (m[j] > 0)
+ if (a[j] > 0)
+ m2 = m[j], a2 = m[j] - a[j];
+ else
+ a2 = m[j], m2 = m[j] + a[j];
+ else
+ if (a[j] > 0)
+ m2 = m[j], a2 = m[j] + a[j];
+ else
+ a2 = m[j], m2 = m[j] - a[j];
+ m[j] = m2;
+ a[j] = a2;
+ }
+ }
+ CHECK(f);
+
+ // finish decoding the floors
+#ifndef STB_VORBIS_NO_DEFER_FLOOR
+ for (i=0; i < f->channels; ++i) {
+ if (really_zero_channel[i]) {
+ memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2);
+ } else {
+ do_floor(f, map, i, n, f->channel_buffers[i], f->finalY[i], NULL);
+ }
+ }
+#else
+ for (i=0; i < f->channels; ++i) {
+ if (really_zero_channel[i]) {
+ memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2);
+ } else {
+ for (j=0; j < n2; ++j)
+ f->channel_buffers[i][j] *= f->floor_buffers[i][j];
+ }
+ }
+#endif
+
+// INVERSE MDCT
+ CHECK(f);
+ for (i=0; i < f->channels; ++i)
+ inverse_mdct(f->channel_buffers[i], n, f, m->blockflag);
+ CHECK(f);
+
+ // this shouldn't be necessary, unless we exited on an error
+ // and want to flush to get to the next packet
+ flush_packet(f);
+
+ if (f->first_decode) {
+ // assume we start so first non-discarded sample is sample 0
+ // this isn't to spec, but spec would require us to read ahead
+ // and decode the size of all current frames--could be done,
+ // but presumably it's not a commonly used feature
+ f->current_loc = -n2; // start of first frame is positioned for discard
+ // we might have to discard samples "from" the next frame too,
+ // if we're lapping a large block then a small at the start?
+ f->discard_samples_deferred = n - right_end;
+ f->current_loc_valid = TRUE;
+ f->first_decode = FALSE;
+ } else if (f->discard_samples_deferred) {
+ if (f->discard_samples_deferred >= right_start - left_start) {
+ f->discard_samples_deferred -= (right_start - left_start);
+ left_start = right_start;
+ *p_left = left_start;
+ } else {
+ left_start += f->discard_samples_deferred;
+ *p_left = left_start;
+ f->discard_samples_deferred = 0;
+ }
+ } else if (f->previous_length == 0 && f->current_loc_valid) {
+ // we're recovering from a seek... that means we're going to discard
+ // the samples from this packet even though we know our position from
+ // the last page header, so we need to update the position based on
+ // the discarded samples here
+ // but wait, the code below is going to add this in itself even
+ // on a discard, so we don't need to do it here...
+ }
+
+ // check if we have ogg information about the sample # for this packet
+ if (f->last_seg_which == f->end_seg_with_known_loc) {
+ // if we have a valid current loc, and this is final:
+ if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) {
+ uint32 current_end = f->known_loc_for_packet - (n-right_end);
+ // then let's infer the size of the (probably) short final frame
+ if (current_end < f->current_loc + (right_end-left_start)) {
+ if (current_end < f->current_loc) {
+ // negative truncation, that's impossible!
+ *len = 0;
+ } else {
+ *len = current_end - f->current_loc;
+ }
+ *len += left_start;
+ if (*len > right_end) *len = right_end; // this should never happen
+ f->current_loc += *len;
+ return TRUE;
+ }
+ }
+ // otherwise, just set our sample loc
+ // guess that the ogg granule pos refers to the _middle_ of the
+ // last frame?
+ // set f->current_loc to the position of left_start
+ f->current_loc = f->known_loc_for_packet - (n2-left_start);
+ f->current_loc_valid = TRUE;
+ }
+ if (f->current_loc_valid)
+ f->current_loc += (right_start - left_start);
+
+ if (f->alloc.alloc_buffer)
+ assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
+ *len = right_end; // ignore samples after the window goes to 0
+ CHECK(f);
+
+ return TRUE;
+}
+
+static int vorbis_decode_packet(vorb *f, int *len, int *p_left, int *p_right)
+{
+ int mode, left_end, right_end;
+ if (!vorbis_decode_initial(f, p_left, &left_end, p_right, &right_end, &mode)) return 0;
+ return vorbis_decode_packet_rest(f, len, f->mode_config + mode, *p_left, left_end, *p_right, right_end, p_left);
+}
+
+static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right)
+{
+ int prev,i,j;
+ // we use right&left (the start of the right- and left-window sin()-regions)
+ // to determine how much to return, rather than inferring from the rules
+ // (same result, clearer code); 'left' indicates where our sin() window
+ // starts, therefore where the previous window's right edge starts, and
+ // therefore where to start mixing from the previous buffer. 'right'
+ // indicates where our sin() ending-window starts, therefore that's where
+ // we start saving, and where our returned-data ends.
+
+ // mixin from previous window
+ if (f->previous_length) {
+ int i,j, n = f->previous_length;
+ float *w = get_window(f, n);
+ for (i=0; i < f->channels; ++i) {
+ for (j=0; j < n; ++j)
+ f->channel_buffers[i][left+j] =
+ f->channel_buffers[i][left+j]*w[ j] +
+ f->previous_window[i][ j]*w[n-1-j];
+ }
+ }
+
+ prev = f->previous_length;
+
+ // last half of this data becomes previous window
+ f->previous_length = len - right;
+
+ // @OPTIMIZE: could avoid this copy by double-buffering the
+ // output (flipping previous_window with channel_buffers), but
+ // then previous_window would have to be 2x as large, and
+ // channel_buffers couldn't be temp mem (although they're NOT
+ // currently temp mem, they could be (unless we want to level
+ // performance by spreading out the computation))
+ for (i=0; i < f->channels; ++i)
+ for (j=0; right+j < len; ++j)
+ f->previous_window[i][j] = f->channel_buffers[i][right+j];
+
+ if (!prev)
+ // there was no previous packet, so this data isn't valid...
+ // this isn't entirely true, only the would-have-overlapped data
+ // isn't valid, but this seems to be what the spec requires
+ return 0;
+
+ // truncate a short frame
+ if (len < right) right = len;
+
+ f->samples_output += right-left;
+
+ return right - left;
+}
+
+static void vorbis_pump_first_frame(stb_vorbis *f)
+{
+ int len, right, left;
+ if (vorbis_decode_packet(f, &len, &left, &right))
+ vorbis_finish_frame(f, len, left, right);
+}
+
+#ifndef STB_VORBIS_NO_PUSHDATA_API
+static int is_whole_packet_present(stb_vorbis *f, int end_page)
+{
+ // make sure that we have the packet available before continuing...
+ // this requires a full ogg parse, but we know we can fetch from f->stream
+
+ // instead of coding this out explicitly, we could save the current read state,
+ // read the next packet with get8() until end-of-packet, check f->eof, then
+ // reset the state? but that would be slower, esp. since we'd have over 256 bytes
+ // of state to restore (primarily the page segment table)
+
+ int s = f->next_seg, first = TRUE;
+ uint8 *p = f->stream;
+
+ if (s != -1) { // if we're not starting the packet with a 'continue on next page' flag
+ for (; s < f->segment_count; ++s) {
+ p += f->segments[s];
+ if (f->segments[s] < 255) // stop at first short segment
+ break;
+ }
+ // either this continues, or it ends it...
+ if (end_page)
+ if (s < f->segment_count-1) return error(f, VORBIS_invalid_stream);
+ if (s == f->segment_count)
+ s = -1; // set 'crosses page' flag
+ if (p > f->stream_end) return error(f, VORBIS_need_more_data);
+ first = FALSE;
+ }
+ for (; s == -1;) {
+ uint8 *q;
+ int n;
+
+ // check that we have the page header ready
+ if (p + 26 >= f->stream_end) return error(f, VORBIS_need_more_data);
+ // validate the page
+ if (memcmp(p, ogg_page_header, 4)) return error(f, VORBIS_invalid_stream);
+ if (p[4] != 0) return error(f, VORBIS_invalid_stream);
+ if (first) { // the first segment must NOT have 'continued_packet', later ones MUST
+ if (f->previous_length)
+ if ((p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream);
+ // if no previous length, we're resynching, so we can come in on a continued-packet,
+ // which we'll just drop
+ } else {
+ if (!(p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream);
+ }
+ n = p[26]; // segment counts
+ q = p+27; // q points to segment table
+ p = q + n; // advance past header
+ // make sure we've read the segment table
+ if (p > f->stream_end) return error(f, VORBIS_need_more_data);
+ for (s=0; s < n; ++s) {
+ p += q[s];
+ if (q[s] < 255)
+ break;
+ }
+ if (end_page)
+ if (s < n-1) return error(f, VORBIS_invalid_stream);
+ if (s == n)
+ s = -1; // set 'crosses page' flag
+ if (p > f->stream_end) return error(f, VORBIS_need_more_data);
+ first = FALSE;
+ }
+ return TRUE;
+}
+#endif // !STB_VORBIS_NO_PUSHDATA_API
+
+static int start_decoder(vorb *f)
+{
+ uint8 header[6], x,y;
+ int len,i,j,k, max_submaps = 0;
+ int longest_floorlist=0;
+
+ // first page, first packet
+
+ if (!start_page(f)) return FALSE;
+ // validate page flag
+ if (!(f->page_flag & PAGEFLAG_first_page)) return error(f, VORBIS_invalid_first_page);
+ if (f->page_flag & PAGEFLAG_last_page) return error(f, VORBIS_invalid_first_page);
+ if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page);
+ // check for expected packet length
+ if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page);
+ if (f->segments[0] != 30) return error(f, VORBIS_invalid_first_page);
+ // read packet
+ // check packet header
+ if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page);
+ if (!getn(f, header, 6)) return error(f, VORBIS_unexpected_eof);
+ if (!vorbis_validate(header)) return error(f, VORBIS_invalid_first_page);
+ // vorbis_version
+ if (get32(f) != 0) return error(f, VORBIS_invalid_first_page);
+ f->channels = get8(f); if (!f->channels) return error(f, VORBIS_invalid_first_page);
+ if (f->channels > STB_VORBIS_MAX_CHANNELS) return error(f, VORBIS_too_many_channels);
+ f->sample_rate = get32(f); if (!f->sample_rate) return error(f, VORBIS_invalid_first_page);
+ get32(f); // bitrate_maximum
+ get32(f); // bitrate_nominal
+ get32(f); // bitrate_minimum
+ x = get8(f);
+ {
+ int log0,log1;
+ log0 = x & 15;
+ log1 = x >> 4;
+ f->blocksize_0 = 1 << log0;
+ f->blocksize_1 = 1 << log1;
+ if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup);
+ if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup);
+ if (log0 > log1) return error(f, VORBIS_invalid_setup);
+ }
+
+ // framing_flag
+ x = get8(f);
+ if (!(x & 1)) return error(f, VORBIS_invalid_first_page);
+
+ // second packet!
+ if (!start_page(f)) return FALSE;
+
+ if (!start_packet(f)) return FALSE;
+ do {
+ len = next_segment(f);
+ skip(f, len);
+ f->bytes_in_seg = 0;
+ } while (len);
+
+ // third packet!
+ if (!start_packet(f)) return FALSE;
+
+ #ifndef STB_VORBIS_NO_PUSHDATA_API
+ if (IS_PUSH_MODE(f)) {
+ if (!is_whole_packet_present(f, TRUE)) {
+ // convert error in ogg header to write type
+ if (f->error == VORBIS_invalid_stream)
+ f->error = VORBIS_invalid_setup;
+ return FALSE;
+ }
+ }
+ #endif
+
+ crc32_init(); // always init it, to avoid multithread race conditions
+
+ if (get8_packet(f) != VORBIS_packet_setup) return error(f, VORBIS_invalid_setup);
+ for (i=0; i < 6; ++i) header[i] = get8_packet(f);
+ if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup);
+
+ // codebooks
+
+ f->codebook_count = get_bits(f,8) + 1;
+ f->codebooks = (Codebook *) setup_malloc(f, sizeof(*f->codebooks) * f->codebook_count);
+ if (f->codebooks == NULL) return error(f, VORBIS_outofmem);
+ memset(f->codebooks, 0, sizeof(*f->codebooks) * f->codebook_count);
+ for (i=0; i < f->codebook_count; ++i) {
+ uint32 *values;
+ int ordered, sorted_count;
+ int total=0;
+ uint8 *lengths;
+ Codebook *c = f->codebooks+i;
+ CHECK(f);
+ x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup);
+ x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup);
+ x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup);
+ x = get_bits(f, 8);
+ c->dimensions = (get_bits(f, 8)<<8) + x;
+ x = get_bits(f, 8);
+ y = get_bits(f, 8);
+ c->entries = (get_bits(f, 8)<<16) + (y<<8) + x;
+ ordered = get_bits(f,1);
+ c->sparse = ordered ? 0 : get_bits(f,1);
+
+ if (c->dimensions == 0 && c->entries != 0) return error(f, VORBIS_invalid_setup);
+
+ if (c->sparse)
+ lengths = (uint8 *) setup_temp_malloc(f, c->entries);
+ else
+ lengths = c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries);
+
+ if (!lengths) return error(f, VORBIS_outofmem);
+
+ if (ordered) {
+ int current_entry = 0;
+ int current_length = get_bits(f,5) + 1;
+ while (current_entry < c->entries) {
+ int limit = c->entries - current_entry;
+ int n = get_bits(f, ilog(limit));
+ if (current_entry + n > (int) c->entries) { return error(f, VORBIS_invalid_setup); }
+ memset(lengths + current_entry, current_length, n);
+ current_entry += n;
+ ++current_length;
+ }
+ } else {
+ for (j=0; j < c->entries; ++j) {
+ int present = c->sparse ? get_bits(f,1) : 1;
+ if (present) {
+ lengths[j] = get_bits(f, 5) + 1;
+ ++total;
+ if (lengths[j] == 32)
+ return error(f, VORBIS_invalid_setup);
+ } else {
+ lengths[j] = NO_CODE;
+ }
+ }
+ }
+
+ if (c->sparse && total >= c->entries >> 2) {
+ // convert sparse items to non-sparse!
+ if (c->entries > (int) f->setup_temp_memory_required)
+ f->setup_temp_memory_required = c->entries;
+
+ c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries);
+ if (c->codeword_lengths == NULL) return error(f, VORBIS_outofmem);
+ memcpy(c->codeword_lengths, lengths, c->entries);
+ setup_temp_free(f, lengths, c->entries); // note this is only safe if there have been no intervening temp mallocs!
+ lengths = c->codeword_lengths;
+ c->sparse = 0;
+ }
+
+ // compute the size of the sorted tables
+ if (c->sparse) {
+ sorted_count = total;
+ } else {
+ sorted_count = 0;
+ #ifndef STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH
+ for (j=0; j < c->entries; ++j)
+ if (lengths[j] > STB_VORBIS_FAST_HUFFMAN_LENGTH && lengths[j] != NO_CODE)
+ ++sorted_count;
+ #endif
+ }
+
+ c->sorted_entries = sorted_count;
+ values = NULL;
+
+ CHECK(f);
+ if (!c->sparse) {
+ c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries);
+ if (!c->codewords) return error(f, VORBIS_outofmem);
+ } else {
+ unsigned int size;
+ if (c->sorted_entries) {
+ c->codeword_lengths = (uint8 *) setup_malloc(f, c->sorted_entries);
+ if (!c->codeword_lengths) return error(f, VORBIS_outofmem);
+ c->codewords = (uint32 *) setup_temp_malloc(f, sizeof(*c->codewords) * c->sorted_entries);
+ if (!c->codewords) return error(f, VORBIS_outofmem);
+ values = (uint32 *) setup_temp_malloc(f, sizeof(*values) * c->sorted_entries);
+ if (!values) return error(f, VORBIS_outofmem);
+ }
+ size = c->entries + (sizeof(*c->codewords) + sizeof(*values)) * c->sorted_entries;
+ if (size > f->setup_temp_memory_required)
+ f->setup_temp_memory_required = size;
+ }
+
+ if (!compute_codewords(c, lengths, c->entries, values)) {
+ if (c->sparse) setup_temp_free(f, values, 0);
+ return error(f, VORBIS_invalid_setup);
+ }
+
+ if (c->sorted_entries) {
+ // allocate an extra slot for sentinels
+ c->sorted_codewords = (uint32 *) setup_malloc(f, sizeof(*c->sorted_codewords) * (c->sorted_entries+1));
+ if (c->sorted_codewords == NULL) return error(f, VORBIS_outofmem);
+ // allocate an extra slot at the front so that c->sorted_values[-1] is defined
+ // so that we can catch that case without an extra if
+ c->sorted_values = ( int *) setup_malloc(f, sizeof(*c->sorted_values ) * (c->sorted_entries+1));
+ if (c->sorted_values == NULL) return error(f, VORBIS_outofmem);
+ ++c->sorted_values;
+ c->sorted_values[-1] = -1;
+ compute_sorted_huffman(c, lengths, values);
+ }
+
+ if (c->sparse) {
+ setup_temp_free(f, values, sizeof(*values)*c->sorted_entries);
+ setup_temp_free(f, c->codewords, sizeof(*c->codewords)*c->sorted_entries);
+ setup_temp_free(f, lengths, c->entries);
+ c->codewords = NULL;
+ }
+
+ compute_accelerated_huffman(c);
+
+ CHECK(f);
+ c->lookup_type = get_bits(f, 4);
+ if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup);
+ if (c->lookup_type > 0) {
+ uint16 *mults;
+ c->minimum_value = float32_unpack(get_bits(f, 32));
+ c->delta_value = float32_unpack(get_bits(f, 32));
+ c->value_bits = get_bits(f, 4)+1;
+ c->sequence_p = get_bits(f,1);
+ if (c->lookup_type == 1) {
+ c->lookup_values = lookup1_values(c->entries, c->dimensions);
+ } else {
+ c->lookup_values = c->entries * c->dimensions;
+ }
+ if (c->lookup_values == 0) return error(f, VORBIS_invalid_setup);
+ mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values);
+ if (mults == NULL) return error(f, VORBIS_outofmem);
+ for (j=0; j < (int) c->lookup_values; ++j) {
+ int q = get_bits(f, c->value_bits);
+ if (q == EOP) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_invalid_setup); }
+ mults[j] = q;
+ }
+
+#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ if (c->lookup_type == 1) {
+ int len, sparse = c->sparse;
+ float last=0;
+ // pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop
+ if (sparse) {
+ if (c->sorted_entries == 0) goto skip;
+ c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->sorted_entries * c->dimensions);
+ } else
+ c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->entries * c->dimensions);
+ if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); }
+ len = sparse ? c->sorted_entries : c->entries;
+ for (j=0; j < len; ++j) {
+ unsigned int z = sparse ? c->sorted_values[j] : j;
+ unsigned int div=1;
+ for (k=0; k < c->dimensions; ++k) {
+ int off = (z / div) % c->lookup_values;
+ float val = mults[off];
+ val = mults[off]*c->delta_value + c->minimum_value + last;
+ c->multiplicands[j*c->dimensions + k] = val;
+ if (c->sequence_p)
+ last = val;
+ if (k+1 < c->dimensions) {
+ if (div > UINT_MAX / (unsigned int) c->lookup_values) {
+ setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
+ return error(f, VORBIS_invalid_setup);
+ }
+ div *= c->lookup_values;
+ }
+ }
+ }
+ c->lookup_type = 2;
+ }
+ else
+#endif
+ {
+ float last=0;
+ CHECK(f);
+ c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values);
+ if (c->multiplicands == NULL) { setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); }
+ for (j=0; j < (int) c->lookup_values; ++j) {
+ float val = mults[j] * c->delta_value + c->minimum_value + last;
+ c->multiplicands[j] = val;
+ if (c->sequence_p)
+ last = val;
+ }
+ }
+#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
+ skip:;
+#endif
+ setup_temp_free(f, mults, sizeof(mults[0])*c->lookup_values);
+
+ CHECK(f);
+ }
+ CHECK(f);
+ }
+
+ // time domain transfers (notused)
+
+ x = get_bits(f, 6) + 1;
+ for (i=0; i < x; ++i) {
+ uint32 z = get_bits(f, 16);
+ if (z != 0) return error(f, VORBIS_invalid_setup);
+ }
+
+ // Floors
+ f->floor_count = get_bits(f, 6)+1;
+ f->floor_config = (Floor *) setup_malloc(f, f->floor_count * sizeof(*f->floor_config));
+ if (f->floor_config == NULL) return error(f, VORBIS_outofmem);
+ for (i=0; i < f->floor_count; ++i) {
+ f->floor_types[i] = get_bits(f, 16);
+ if (f->floor_types[i] > 1) return error(f, VORBIS_invalid_setup);
+ if (f->floor_types[i] == 0) {
+ Floor0 *g = &f->floor_config[i].floor0;
+ g->order = get_bits(f,8);
+ g->rate = get_bits(f,16);
+ g->bark_map_size = get_bits(f,16);
+ g->amplitude_bits = get_bits(f,6);
+ g->amplitude_offset = get_bits(f,8);
+ g->number_of_books = get_bits(f,4) + 1;
+ for (j=0; j < g->number_of_books; ++j)
+ g->book_list[j] = get_bits(f,8);
+ return error(f, VORBIS_feature_not_supported);
+ } else {
+ Point p[31*8+2];
+ Floor1 *g = &f->floor_config[i].floor1;
+ int max_class = -1;
+ g->partitions = get_bits(f, 5);
+ for (j=0; j < g->partitions; ++j) {
+ g->partition_class_list[j] = get_bits(f, 4);
+ if (g->partition_class_list[j] > max_class)
+ max_class = g->partition_class_list[j];
+ }
+ for (j=0; j <= max_class; ++j) {
+ g->class_dimensions[j] = get_bits(f, 3)+1;
+ g->class_subclasses[j] = get_bits(f, 2);
+ if (g->class_subclasses[j]) {
+ g->class_masterbooks[j] = get_bits(f, 8);
+ if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
+ }
+ for (k=0; k < 1 << g->class_subclasses[j]; ++k) {
+ g->subclass_books[j][k] = get_bits(f,8)-1;
+ if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
+ }
+ }
+ g->floor1_multiplier = get_bits(f,2)+1;
+ g->rangebits = get_bits(f,4);
+ g->Xlist[0] = 0;
+ g->Xlist[1] = 1 << g->rangebits;
+ g->values = 2;
+ for (j=0; j < g->partitions; ++j) {
+ int c = g->partition_class_list[j];
+ for (k=0; k < g->class_dimensions[c]; ++k) {
+ g->Xlist[g->values] = get_bits(f, g->rangebits);
+ ++g->values;
+ }
+ }
+ // precompute the sorting
+ for (j=0; j < g->values; ++j) {
+ p[j].x = g->Xlist[j];
+ p[j].y = j;
+ }
+ qsort(p, g->values, sizeof(p[0]), point_compare);
+ for (j=0; j < g->values; ++j)
+ g->sorted_order[j] = (uint8) p[j].y;
+ // precompute the neighbors
+ for (j=2; j < g->values; ++j) {
+ int low,hi;
+ neighbors(g->Xlist, j, &low,&hi);
+ g->neighbors[j][0] = low;
+ g->neighbors[j][1] = hi;
+ }
+
+ if (g->values > longest_floorlist)
+ longest_floorlist = g->values;
+ }
+ }
+
+ // Residue
+ f->residue_count = get_bits(f, 6)+1;
+ f->residue_config = (Residue *) setup_malloc(f, f->residue_count * sizeof(f->residue_config[0]));
+ if (f->residue_config == NULL) return error(f, VORBIS_outofmem);
+ memset(f->residue_config, 0, f->residue_count * sizeof(f->residue_config[0]));
+ for (i=0; i < f->residue_count; ++i) {
+ uint8 residue_cascade[64];
+ Residue *r = f->residue_config+i;
+ f->residue_types[i] = get_bits(f, 16);
+ if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup);
+ r->begin = get_bits(f, 24);
+ r->end = get_bits(f, 24);
+ if (r->end < r->begin) return error(f, VORBIS_invalid_setup);
+ r->part_size = get_bits(f,24)+1;
+ r->classifications = get_bits(f,6)+1;
+ r->classbook = get_bits(f,8);
+ if (r->classbook >= f->codebook_count) return error(f, VORBIS_invalid_setup);
+ for (j=0; j < r->classifications; ++j) {
+ uint8 high_bits=0;
+ uint8 low_bits=get_bits(f,3);
+ if (get_bits(f,1))
+ high_bits = get_bits(f,5);
+ residue_cascade[j] = high_bits*8 + low_bits;
+ }
+ r->residue_books = (short (*)[8]) setup_malloc(f, sizeof(r->residue_books[0]) * r->classifications);
+ if (r->residue_books == NULL) return error(f, VORBIS_outofmem);
+ for (j=0; j < r->classifications; ++j) {
+ for (k=0; k < 8; ++k) {
+ if (residue_cascade[j] & (1 << k)) {
+ r->residue_books[j][k] = get_bits(f, 8);
+ if (r->residue_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
+ } else {
+ r->residue_books[j][k] = -1;
+ }
+ }
+ }
+ // precompute the classifications[] array to avoid inner-loop mod/divide
+ // call it 'classdata' since we already have r->classifications
+ r->classdata = (uint8 **) setup_malloc(f, sizeof(*r->classdata) * f->codebooks[r->classbook].entries);
+ if (!r->classdata) return error(f, VORBIS_outofmem);
+ memset(r->classdata, 0, sizeof(*r->classdata) * f->codebooks[r->classbook].entries);
+ for (j=0; j < f->codebooks[r->classbook].entries; ++j) {
+ int classwords = f->codebooks[r->classbook].dimensions;
+ int temp = j;
+ r->classdata[j] = (uint8 *) setup_malloc(f, sizeof(r->classdata[j][0]) * classwords);
+ if (r->classdata[j] == NULL) return error(f, VORBIS_outofmem);
+ for (k=classwords-1; k >= 0; --k) {
+ r->classdata[j][k] = temp % r->classifications;
+ temp /= r->classifications;
+ }
+ }
+ }
+
+ f->mapping_count = get_bits(f,6)+1;
+ f->mapping = (Mapping *) setup_malloc(f, f->mapping_count * sizeof(*f->mapping));
+ if (f->mapping == NULL) return error(f, VORBIS_outofmem);
+ memset(f->mapping, 0, f->mapping_count * sizeof(*f->mapping));
+ for (i=0; i < f->mapping_count; ++i) {
+ Mapping *m = f->mapping + i;
+ int mapping_type = get_bits(f,16);
+ if (mapping_type != 0) return error(f, VORBIS_invalid_setup);
+ m->chan = (MappingChannel *) setup_malloc(f, f->channels * sizeof(*m->chan));
+ if (m->chan == NULL) return error(f, VORBIS_outofmem);
+ if (get_bits(f,1))
+ m->submaps = get_bits(f,4)+1;
+ else
+ m->submaps = 1;
+ if (m->submaps > max_submaps)
+ max_submaps = m->submaps;
+ if (get_bits(f,1)) {
+ m->coupling_steps = get_bits(f,8)+1;
+ for (k=0; k < m->coupling_steps; ++k) {
+ m->chan[k].magnitude = get_bits(f, ilog(f->channels-1));
+ m->chan[k].angle = get_bits(f, ilog(f->channels-1));
+ if (m->chan[k].magnitude >= f->channels) return error(f, VORBIS_invalid_setup);
+ if (m->chan[k].angle >= f->channels) return error(f, VORBIS_invalid_setup);
+ if (m->chan[k].magnitude == m->chan[k].angle) return error(f, VORBIS_invalid_setup);
+ }
+ } else
+ m->coupling_steps = 0;
+
+ // reserved field
+ if (get_bits(f,2)) return error(f, VORBIS_invalid_setup);
+ if (m->submaps > 1) {
+ for (j=0; j < f->channels; ++j) {
+ m->chan[j].mux = get_bits(f, 4);
+ if (m->chan[j].mux >= m->submaps) return error(f, VORBIS_invalid_setup);
+ }
+ } else
+ // @SPECIFICATION: this case is missing from the spec
+ for (j=0; j < f->channels; ++j)
+ m->chan[j].mux = 0;
+
+ for (j=0; j < m->submaps; ++j) {
+ get_bits(f,8); // discard
+ m->submap_floor[j] = get_bits(f,8);
+ m->submap_residue[j] = get_bits(f,8);
+ if (m->submap_floor[j] >= f->floor_count) return error(f, VORBIS_invalid_setup);
+ if (m->submap_residue[j] >= f->residue_count) return error(f, VORBIS_invalid_setup);
+ }
+ }
+
+ // Modes
+ f->mode_count = get_bits(f, 6)+1;
+ for (i=0; i < f->mode_count; ++i) {
+ Mode *m = f->mode_config+i;
+ m->blockflag = get_bits(f,1);
+ m->windowtype = get_bits(f,16);
+ m->transformtype = get_bits(f,16);
+ m->mapping = get_bits(f,8);
+ if (m->windowtype != 0) return error(f, VORBIS_invalid_setup);
+ if (m->transformtype != 0) return error(f, VORBIS_invalid_setup);
+ if (m->mapping >= f->mapping_count) return error(f, VORBIS_invalid_setup);
+ }
+
+ flush_packet(f);
+
+ f->previous_length = 0;
+
+ for (i=0; i < f->channels; ++i) {
+ f->channel_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1);
+ f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2);
+ f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist);
+ if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem);
+ #ifdef STB_VORBIS_NO_DEFER_FLOOR
+ f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2);
+ if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem);
+ #endif
+ }
+
+ if (!init_blocksize(f, 0, f->blocksize_0)) return FALSE;
+ if (!init_blocksize(f, 1, f->blocksize_1)) return FALSE;
+ f->blocksize[0] = f->blocksize_0;
+ f->blocksize[1] = f->blocksize_1;
+
+#ifdef STB_VORBIS_DIVIDE_TABLE
+ if (integer_divide_table[1][1]==0)
+ for (i=0; i < DIVTAB_NUMER; ++i)
+ for (j=1; j < DIVTAB_DENOM; ++j)
+ integer_divide_table[i][j] = i / j;
+#endif
+
+ // compute how much temporary memory is needed
+
+ // 1.
+ {
+ uint32 imdct_mem = (f->blocksize_1 * sizeof(float) >> 1);
+ uint32 classify_mem;
+ int i,max_part_read=0;
+ for (i=0; i < f->residue_count; ++i) {
+ Residue *r = f->residue_config + i;
+ int n_read = r->end - r->begin;
+ int part_read = n_read / r->part_size;
+ if (part_read > max_part_read)
+ max_part_read = part_read;
+ }
+ #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
+ classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(uint8 *));
+ #else
+ classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *));
+ #endif
+
+ f->temp_memory_required = classify_mem;
+ if (imdct_mem > f->temp_memory_required)
+ f->temp_memory_required = imdct_mem;
+ }
+
+ f->first_decode = TRUE;
+
+ if (f->alloc.alloc_buffer) {
+ assert(f->temp_offset == f->alloc.alloc_buffer_length_in_bytes);
+ // check if there's enough temp memory so we don't error later
+ if (f->setup_offset + sizeof(*f) + f->temp_memory_required > (unsigned) f->temp_offset)
+ return error(f, VORBIS_outofmem);
+ }
+
+ f->first_audio_page_offset = stb_vorbis_get_file_offset(f);
+
+ return TRUE;
+}
+
+static void vorbis_deinit(stb_vorbis *p)
+{
+ int i,j;
+ if (p->residue_config) {
+ for (i=0; i < p->residue_count; ++i) {
+ Residue *r = p->residue_config+i;
+ if (r->classdata) {
+ for (j=0; j < p->codebooks[r->classbook].entries; ++j)
+ setup_free(p, r->classdata[j]);
+ setup_free(p, r->classdata);
+ }
+ setup_free(p, r->residue_books);
+ }
+ }
+
+ if (p->codebooks) {
+ CHECK(p);
+ for (i=0; i < p->codebook_count; ++i) {
+ Codebook *c = p->codebooks + i;
+ setup_free(p, c->codeword_lengths);
+ setup_free(p, c->multiplicands);
+ setup_free(p, c->codewords);
+ setup_free(p, c->sorted_codewords);
+ // c->sorted_values[-1] is the first entry in the array
+ setup_free(p, c->sorted_values ? c->sorted_values-1 : NULL);
+ }
+ setup_free(p, p->codebooks);
+ }
+ setup_free(p, p->floor_config);
+ setup_free(p, p->residue_config);
+ if (p->mapping) {
+ for (i=0; i < p->mapping_count; ++i)
+ setup_free(p, p->mapping[i].chan);
+ setup_free(p, p->mapping);
+ }
+ CHECK(p);
+ for (i=0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) {
+ setup_free(p, p->channel_buffers[i]);
+ setup_free(p, p->previous_window[i]);
+ #ifdef STB_VORBIS_NO_DEFER_FLOOR
+ setup_free(p, p->floor_buffers[i]);
+ #endif
+ setup_free(p, p->finalY[i]);
+ }
+ for (i=0; i < 2; ++i) {
+ setup_free(p, p->A[i]);
+ setup_free(p, p->B[i]);
+ setup_free(p, p->C[i]);
+ setup_free(p, p->window[i]);
+ setup_free(p, p->bit_reverse[i]);
+ }
+ #ifndef STB_VORBIS_NO_STDIO
+ if (p->close_on_free) fclose(p->f);
+ #endif
+}
+
+void stb_vorbis_close(stb_vorbis *p)
+{
+ if (p == NULL) return;
+ vorbis_deinit(p);
+ setup_free(p,p);
+}
+
+static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z)
+{
+ memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start
+ if (z) {
+ p->alloc = *z;
+ p->alloc.alloc_buffer_length_in_bytes = (p->alloc.alloc_buffer_length_in_bytes+3) & ~3;
+ p->temp_offset = p->alloc.alloc_buffer_length_in_bytes;
+ }
+ p->eof = 0;
+ p->error = VORBIS__no_error;
+ p->stream = NULL;
+ p->codebooks = NULL;
+ p->page_crc_tests = -1;
+ #ifndef STB_VORBIS_NO_STDIO
+ p->close_on_free = FALSE;
+ p->f = NULL;
+ #endif
+}
+
+int stb_vorbis_get_sample_offset(stb_vorbis *f)
+{
+ if (f->current_loc_valid)
+ return f->current_loc;
+ else
+ return -1;
+}
+
+stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f)
+{
+ stb_vorbis_info d;
+ d.channels = f->channels;
+ d.sample_rate = f->sample_rate;
+ d.setup_memory_required = f->setup_memory_required;
+ d.setup_temp_memory_required = f->setup_temp_memory_required;
+ d.temp_memory_required = f->temp_memory_required;
+ d.max_frame_size = f->blocksize_1 >> 1;
+ return d;
+}
+
+int stb_vorbis_get_error(stb_vorbis *f)
+{
+ int e = f->error;
+ f->error = VORBIS__no_error;
+ return e;
+}
+
+static stb_vorbis * vorbis_alloc(stb_vorbis *f)
+{
+ stb_vorbis *p = (stb_vorbis *) setup_malloc(f, sizeof(*p));
+ return p;
+}
+
+#ifndef STB_VORBIS_NO_PUSHDATA_API
+
+void stb_vorbis_flush_pushdata(stb_vorbis *f)
+{
+ f->previous_length = 0;
+ f->page_crc_tests = 0;
+ f->discard_samples_deferred = 0;
+ f->current_loc_valid = FALSE;
+ f->first_decode = FALSE;
+ f->samples_output = 0;
+ f->channel_buffer_start = 0;
+ f->channel_buffer_end = 0;
+}
+
+static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len)
+{
+ int i,n;
+ for (i=0; i < f->page_crc_tests; ++i)
+ f->scan[i].bytes_done = 0;
+
+ // if we have room for more scans, search for them first, because
+ // they may cause us to stop early if their header is incomplete
+ if (f->page_crc_tests < STB_VORBIS_PUSHDATA_CRC_COUNT) {
+ if (data_len < 4) return 0;
+ data_len -= 3; // need to look for 4-byte sequence, so don't miss
+ // one that straddles a boundary
+ for (i=0; i < data_len; ++i) {
+ if (data[i] == 0x4f) {
+ if (0==memcmp(data+i, ogg_page_header, 4)) {
+ int j,len;
+ uint32 crc;
+ // make sure we have the whole page header
+ if (i+26 >= data_len || i+27+data[i+26] >= data_len) {
+ // only read up to this page start, so hopefully we'll
+ // have the whole page header start next time
+ data_len = i;
+ break;
+ }
+ // ok, we have it all; compute the length of the page
+ len = 27 + data[i+26];
+ for (j=0; j < data[i+26]; ++j)
+ len += data[i+27+j];
+ // scan everything up to the embedded crc (which we must 0)
+ crc = 0;
+ for (j=0; j < 22; ++j)
+ crc = crc32_update(crc, data[i+j]);
+ // now process 4 0-bytes
+ for ( ; j < 26; ++j)
+ crc = crc32_update(crc, 0);
+ // len is the total number of bytes we need to scan
+ n = f->page_crc_tests++;
+ f->scan[n].bytes_left = len-j;
+ f->scan[n].crc_so_far = crc;
+ f->scan[n].goal_crc = data[i+22] + (data[i+23] << 8) + (data[i+24]<<16) + (data[i+25]<<24);
+ // if the last frame on a page is continued to the next, then
+ // we can't recover the sample_loc immediately
+ if (data[i+27+data[i+26]-1] == 255)
+ f->scan[n].sample_loc = ~0;
+ else
+ f->scan[n].sample_loc = data[i+6] + (data[i+7] << 8) + (data[i+ 8]<<16) + (data[i+ 9]<<24);
+ f->scan[n].bytes_done = i+j;
+ if (f->page_crc_tests == STB_VORBIS_PUSHDATA_CRC_COUNT)
+ break;
+ // keep going if we still have room for more
+ }
+ }
+ }
+ }
+
+ for (i=0; i < f->page_crc_tests;) {
+ uint32 crc;
+ int j;
+ int n = f->scan[i].bytes_done;
+ int m = f->scan[i].bytes_left;
+ if (m > data_len - n) m = data_len - n;
+ // m is the bytes to scan in the current chunk
+ crc = f->scan[i].crc_so_far;
+ for (j=0; j < m; ++j)
+ crc = crc32_update(crc, data[n+j]);
+ f->scan[i].bytes_left -= m;
+ f->scan[i].crc_so_far = crc;
+ if (f->scan[i].bytes_left == 0) {
+ // does it match?
+ if (f->scan[i].crc_so_far == f->scan[i].goal_crc) {
+ // Houston, we have page
+ data_len = n+m; // consumption amount is wherever that scan ended
+ f->page_crc_tests = -1; // drop out of page scan mode
+ f->previous_length = 0; // decode-but-don't-output one frame
+ f->next_seg = -1; // start a new page
+ f->current_loc = f->scan[i].sample_loc; // set the current sample location
+ // to the amount we'd have decoded had we decoded this page
+ f->current_loc_valid = f->current_loc != ~0U;
+ return data_len;
+ }
+ // delete entry
+ f->scan[i] = f->scan[--f->page_crc_tests];
+ } else {
+ ++i;
+ }
+ }
+
+ return data_len;
+}
+
+// return value: number of bytes we used
+int stb_vorbis_decode_frame_pushdata(
+ stb_vorbis *f, // the file we're decoding
+ const uint8 *data, int data_len, // the memory available for decoding
+ int *channels, // place to write number of float * buffers
+ float ***output, // place to write float ** array of float * buffers
+ int *samples // place to write number of output samples
+ )
+{
+ int i;
+ int len,right,left;
+
+ if (!IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
+
+ if (f->page_crc_tests >= 0) {
+ *samples = 0;
+ return vorbis_search_for_page_pushdata(f, (uint8 *) data, data_len);
+ }
+
+ f->stream = (uint8 *) data;
+ f->stream_end = (uint8 *) data + data_len;
+ f->error = VORBIS__no_error;
+
+ // check that we have the entire packet in memory
+ if (!is_whole_packet_present(f, FALSE)) {
+ *samples = 0;
+ return 0;
+ }
+
+ if (!vorbis_decode_packet(f, &len, &left, &right)) {
+ // save the actual error we encountered
+ enum STBVorbisError error = f->error;
+ if (error == VORBIS_bad_packet_type) {
+ // flush and resynch
+ f->error = VORBIS__no_error;
+ while (get8_packet(f) != EOP)
+ if (f->eof) break;
+ *samples = 0;
+ return (int) (f->stream - data);
+ }
+ if (error == VORBIS_continued_packet_flag_invalid) {
+ if (f->previous_length == 0) {
+ // we may be resynching, in which case it's ok to hit one
+ // of these; just discard the packet
+ f->error = VORBIS__no_error;
+ while (get8_packet(f) != EOP)
+ if (f->eof) break;
+ *samples = 0;
+ return (int) (f->stream - data);
+ }
+ }
+ // if we get an error while parsing, what to do?
+ // well, it DEFINITELY won't work to continue from where we are!
+ stb_vorbis_flush_pushdata(f);
+ // restore the error that actually made us bail
+ f->error = error;
+ *samples = 0;
+ return 1;
+ }
+
+ // success!
+ len = vorbis_finish_frame(f, len, left, right);
+ for (i=0; i < f->channels; ++i)
+ f->outputs[i] = f->channel_buffers[i] + left;
+
+ if (channels) *channels = f->channels;
+ *samples = len;
+ *output = f->outputs;
+ return (int) (f->stream - data);
+}
+
+stb_vorbis *stb_vorbis_open_pushdata(
+ const unsigned char *data, int data_len, // the memory available for decoding
+ int *data_used, // only defined if result is not NULL
+ int *error, const stb_vorbis_alloc *alloc)
+{
+ stb_vorbis *f, p;
+ vorbis_init(&p, alloc);
+ p.stream = (uint8 *) data;
+ p.stream_end = (uint8 *) data + data_len;
+ p.push_mode = TRUE;
+ if (!start_decoder(&p)) {
+ if (p.eof)
+ *error = VORBIS_need_more_data;
+ else
+ *error = p.error;
+ return NULL;
+ }
+ f = vorbis_alloc(&p);
+ if (f) {
+ *f = p;
+ *data_used = (int) (f->stream - data);
+ *error = 0;
+ return f;
+ } else {
+ vorbis_deinit(&p);
+ return NULL;
+ }
+}
+#endif // STB_VORBIS_NO_PUSHDATA_API
+
+unsigned int stb_vorbis_get_file_offset(stb_vorbis *f)
+{
+ #ifndef STB_VORBIS_NO_PUSHDATA_API
+ if (f->push_mode) return 0;
+ #endif
+ if (USE_MEMORY(f)) return (unsigned int) (f->stream - f->stream_start);
+ #ifndef STB_VORBIS_NO_STDIO
+ return (unsigned int) (ftell(f->f) - f->f_start);
+ #endif
+}
+
+#ifndef STB_VORBIS_NO_PULLDATA_API
+//
+// DATA-PULLING API
+//
+
+static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last)
+{
+ for(;;) {
+ int n;
+ if (f->eof) return 0;
+ n = get8(f);
+ if (n == 0x4f) { // page header candidate
+ unsigned int retry_loc = stb_vorbis_get_file_offset(f);
+ int i;
+ // check if we're off the end of a file_section stream
+ if (retry_loc - 25 > f->stream_len)
+ return 0;
+ // check the rest of the header
+ for (i=1; i < 4; ++i)
+ if (get8(f) != ogg_page_header[i])
+ break;
+ if (f->eof) return 0;
+ if (i == 4) {
+ uint8 header[27];
+ uint32 i, crc, goal, len;
+ for (i=0; i < 4; ++i)
+ header[i] = ogg_page_header[i];
+ for (; i < 27; ++i)
+ header[i] = get8(f);
+ if (f->eof) return 0;
+ if (header[4] != 0) goto invalid;
+ goal = header[22] + (header[23] << 8) + (header[24]<<16) + (header[25]<<24);
+ for (i=22; i < 26; ++i)
+ header[i] = 0;
+ crc = 0;
+ for (i=0; i < 27; ++i)
+ crc = crc32_update(crc, header[i]);
+ len = 0;
+ for (i=0; i < header[26]; ++i) {
+ int s = get8(f);
+ crc = crc32_update(crc, s);
+ len += s;
+ }
+ if (len && f->eof) return 0;
+ for (i=0; i < len; ++i)
+ crc = crc32_update(crc, get8(f));
+ // finished parsing probable page
+ if (crc == goal) {
+ // we could now check that it's either got the last
+ // page flag set, OR it's followed by the capture
+ // pattern, but I guess TECHNICALLY you could have
+ // a file with garbage between each ogg page and recover
+ // from it automatically? So even though that paranoia
+ // might decrease the chance of an invalid decode by
+ // another 2^32, not worth it since it would hose those
+ // invalid-but-useful files?
+ if (end)
+ *end = stb_vorbis_get_file_offset(f);
+ if (last) {
+ if (header[5] & 0x04)
+ *last = 1;
+ else
+ *last = 0;
+ }
+ set_file_offset(f, retry_loc-1);
+ return 1;
+ }
+ }
+ invalid:
+ // not a valid page, so rewind and look for next one
+ set_file_offset(f, retry_loc);
+ }
+ }
+}
+
+
+#define SAMPLE_unknown 0xffffffff
+
+// seeking is implemented with a binary search, which narrows down the range to
+// 64K, before using a linear search (because finding the synchronization
+// pattern can be expensive, and the chance we'd find the end page again is
+// relatively high for small ranges)
+//
+// two initial interpolation-style probes are used at the start of the search
+// to try to bound either side of the binary search sensibly, while still
+// working in O(log n) time if they fail.
+
+static int get_seek_page_info(stb_vorbis *f, ProbedPage *z)
+{
+ uint8 header[27], lacing[255];
+ int i,len;
+
+ // record where the page starts
+ z->page_start = stb_vorbis_get_file_offset(f);
+
+ // parse the header
+ getn(f, header, 27);
+ if (header[0] != 'O' || header[1] != 'g' || header[2] != 'g' || header[3] != 'S')
+ return 0;
+ getn(f, lacing, header[26]);
+
+ // determine the length of the payload
+ len = 0;
+ for (i=0; i < header[26]; ++i)
+ len += lacing[i];
+
+ // this implies where the page ends
+ z->page_end = z->page_start + 27 + header[26] + len;
+
+ // read the last-decoded sample out of the data
+ z->last_decoded_sample = header[6] + (header[7] << 8) + (header[8] << 16) + (header[9] << 24);
+
+ // restore file state to where we were
+ set_file_offset(f, z->page_start);
+ return 1;
+}
+
+// rarely used function to seek back to the preceeding page while finding the
+// start of a packet
+static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset)
+{
+ unsigned int previous_safe, end;
+
+ // now we want to seek back 64K from the limit
+ if (limit_offset >= 65536 && limit_offset-65536 >= f->first_audio_page_offset)
+ previous_safe = limit_offset - 65536;
+ else
+ previous_safe = f->first_audio_page_offset;
+
+ set_file_offset(f, previous_safe);
+
+ while (vorbis_find_page(f, &end, NULL)) {
+ if (end >= limit_offset && stb_vorbis_get_file_offset(f) < limit_offset)
+ return 1;
+ set_file_offset(f, end);
+ }
+
+ return 0;
+}
+
+// implements the search logic for finding a page and starting decoding. if
+// the function succeeds, current_loc_valid will be true and current_loc will
+// be less than or equal to the provided sample number (the closer the
+// better).
+static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
+{
+ ProbedPage left, right, mid;
+ int i, start_seg_with_known_loc, end_pos, page_start;
+ uint32 delta, stream_length, padding;
+ double offset, bytes_per_sample;
+ int probe = 0;
+
+ // find the last page and validate the target sample
+ stream_length = stb_vorbis_stream_length_in_samples(f);
+ if (stream_length == 0) return error(f, VORBIS_seek_without_length);
+ if (sample_number > stream_length) return error(f, VORBIS_seek_invalid);
+
+ // this is the maximum difference between the window-center (which is the
+ // actual granule position value), and the right-start (which the spec
+ // indicates should be the granule position (give or take one)).
+ padding = ((f->blocksize_1 - f->blocksize_0) >> 2);
+ if (sample_number < padding)
+ sample_number = 0;
+ else
+ sample_number -= padding;
+
+ left = f->p_first;
+ while (left.last_decoded_sample == ~0U) {
+ // (untested) the first page does not have a 'last_decoded_sample'
+ set_file_offset(f, left.page_end);
+ if (!get_seek_page_info(f, &left)) goto error;
+ }
+
+ right = f->p_last;
+ assert(right.last_decoded_sample != ~0U);
+
+ // starting from the start is handled differently
+ if (sample_number <= left.last_decoded_sample) {
+ stb_vorbis_seek_start(f);
+ return 1;
+ }
+
+ while (left.page_end != right.page_start) {
+ assert(left.page_end < right.page_start);
+ // search range in bytes
+ delta = right.page_start - left.page_end;
+ if (delta <= 65536) {
+ // there's only 64K left to search - handle it linearly
+ set_file_offset(f, left.page_end);
+ } else {
+ if (probe < 2) {
+ if (probe == 0) {
+ // first probe (interpolate)
+ double data_bytes = right.page_end - left.page_start;
+ bytes_per_sample = data_bytes / right.last_decoded_sample;
+ offset = left.page_start + bytes_per_sample * (sample_number - left.last_decoded_sample);
+ } else {
+ // second probe (try to bound the other side)
+ double error = ((double) sample_number - mid.last_decoded_sample) * bytes_per_sample;
+ if (error >= 0 && error < 8000) error = 8000;
+ if (error < 0 && error > -8000) error = -8000;
+ offset += error * 2;
+ }
+
+ // ensure the offset is valid
+ if (offset < left.page_end)
+ offset = left.page_end;
+ if (offset > right.page_start - 65536)
+ offset = right.page_start - 65536;
+
+ set_file_offset(f, (unsigned int) offset);
+ } else {
+ // binary search for large ranges (offset by 32K to ensure
+ // we don't hit the right page)
+ set_file_offset(f, left.page_end + (delta / 2) - 32768);
+ }
+
+ if (!vorbis_find_page(f, NULL, NULL)) goto error;
+ }
+
+ for (;;) {
+ if (!get_seek_page_info(f, &mid)) goto error;
+ if (mid.last_decoded_sample != ~0U) break;
+ // (untested) no frames end on this page
+ set_file_offset(f, mid.page_end);
+ assert(mid.page_start < right.page_start);
+ }
+
+ // if we've just found the last page again then we're in a tricky file,
+ // and we're close enough.
+ if (mid.page_start == right.page_start)
+ break;
+
+ if (sample_number < mid.last_decoded_sample)
+ right = mid;
+ else
+ left = mid;
+
+ ++probe;
+ }
+
+ // seek back to start of the last packet
+ page_start = left.page_start;
+ set_file_offset(f, page_start);
+ if (!start_page(f)) return error(f, VORBIS_seek_failed);
+ end_pos = f->end_seg_with_known_loc;
+ assert(end_pos >= 0);
+
+ for (;;) {
+ for (i = end_pos; i > 0; --i)
+ if (f->segments[i-1] != 255)
+ break;
+
+ start_seg_with_known_loc = i;
+
+ if (start_seg_with_known_loc > 0 || !(f->page_flag & PAGEFLAG_continued_packet))
+ break;
+
+ // (untested) the final packet begins on an earlier page
+ if (!go_to_page_before(f, page_start))
+ goto error;
+
+ page_start = stb_vorbis_get_file_offset(f);
+ if (!start_page(f)) goto error;
+ end_pos = f->segment_count - 1;
+ }
+
+ // prepare to start decoding
+ f->current_loc_valid = FALSE;
+ f->last_seg = FALSE;
+ f->valid_bits = 0;
+ f->packet_bytes = 0;
+ f->bytes_in_seg = 0;
+ f->previous_length = 0;
+ f->next_seg = start_seg_with_known_loc;
+
+ for (i = 0; i < start_seg_with_known_loc; i++)
+ skip(f, f->segments[i]);
+
+ // start decoding (optimizable - this frame is generally discarded)
+ vorbis_pump_first_frame(f);
+ return 1;
+
+error:
+ // try to restore the file to a valid state
+ stb_vorbis_seek_start(f);
+ return error(f, VORBIS_seek_failed);
+}
+
+// the same as vorbis_decode_initial, but without advancing
+static int peek_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode)
+{
+ int bits_read, bytes_read;
+
+ if (!vorbis_decode_initial(f, p_left_start, p_left_end, p_right_start, p_right_end, mode))
+ return 0;
+
+ // either 1 or 2 bytes were read, figure out which so we can rewind
+ bits_read = 1 + ilog(f->mode_count-1);
+ if (f->mode_config[*mode].blockflag)
+ bits_read += 2;
+ bytes_read = (bits_read + 7) / 8;
+
+ f->bytes_in_seg += bytes_read;
+ f->packet_bytes -= bytes_read;
+ skip(f, -bytes_read);
+ if (f->next_seg == -1)
+ f->next_seg = f->segment_count - 1;
+ else
+ f->next_seg--;
+ f->valid_bits = 0;
+
+ return 1;
+}
+
+int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number)
+{
+ uint32 max_frame_samples;
+
+ if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
+
+ // fast page-level search
+ if (!seek_to_sample_coarse(f, sample_number))
+ return 0;
+
+ assert(f->current_loc_valid);
+ assert(f->current_loc <= sample_number);
+
+ // linear search for the relevant packet
+ max_frame_samples = (f->blocksize_1*3 - f->blocksize_0) >> 2;
+ while (f->current_loc < sample_number) {
+ int left_start, left_end, right_start, right_end, mode, frame_samples;
+ if (!peek_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode))
+ return error(f, VORBIS_seek_failed);
+ // calculate the number of samples returned by the next frame
+ frame_samples = right_start - left_start;
+ if (f->current_loc + frame_samples > sample_number) {
+ return 1; // the next frame will contain the sample
+ } else if (f->current_loc + frame_samples + max_frame_samples > sample_number) {
+ // there's a chance the frame after this could contain the sample
+ vorbis_pump_first_frame(f);
+ } else {
+ // this frame is too early to be relevant
+ f->current_loc += frame_samples;
+ f->previous_length = 0;
+ maybe_start_packet(f);
+ flush_packet(f);
+ }
+ }
+ // the next frame will start with the sample
+ assert(f->current_loc == sample_number);
+ return 1;
+}
+
+int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number)
+{
+ if (!stb_vorbis_seek_frame(f, sample_number))
+ return 0;
+
+ if (sample_number != f->current_loc) {
+ int n;
+ uint32 frame_start = f->current_loc;
+ stb_vorbis_get_frame_float(f, &n, NULL);
+ assert(sample_number > frame_start);
+ assert(f->channel_buffer_start + (int) (sample_number-frame_start) <= f->channel_buffer_end);
+ f->channel_buffer_start += (sample_number - frame_start);
+ }
+
+ return 1;
+}
+
+void stb_vorbis_seek_start(stb_vorbis *f)
+{
+ if (IS_PUSH_MODE(f)) { error(f, VORBIS_invalid_api_mixing); return; }
+ set_file_offset(f, f->first_audio_page_offset);
+ f->previous_length = 0;
+ f->first_decode = TRUE;
+ f->next_seg = -1;
+ vorbis_pump_first_frame(f);
+}
+
+unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f)
+{
+ unsigned int restore_offset, previous_safe;
+ unsigned int end, last_page_loc;
+
+ if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
+ if (!f->total_samples) {
+ unsigned int last;
+ uint32 lo,hi;
+ char header[6];
+
+ // first, store the current decode position so we can restore it
+ restore_offset = stb_vorbis_get_file_offset(f);
+
+ // now we want to seek back 64K from the end (the last page must
+ // be at most a little less than 64K, but let's allow a little slop)
+ if (f->stream_len >= 65536 && f->stream_len-65536 >= f->first_audio_page_offset)
+ previous_safe = f->stream_len - 65536;
+ else
+ previous_safe = f->first_audio_page_offset;
+
+ set_file_offset(f, previous_safe);
+ // previous_safe is now our candidate 'earliest known place that seeking
+ // to will lead to the final page'
+
+ if (!vorbis_find_page(f, &end, &last)) {
+ // if we can't find a page, we're hosed!
+ f->error = VORBIS_cant_find_last_page;
+ f->total_samples = 0xffffffff;
+ goto done;
+ }
+
+ // check if there are more pages
+ last_page_loc = stb_vorbis_get_file_offset(f);
+
+ // stop when the last_page flag is set, not when we reach eof;
+ // this allows us to stop short of a 'file_section' end without
+ // explicitly checking the length of the section
+ while (!last) {
+ set_file_offset(f, end);
+ if (!vorbis_find_page(f, &end, &last)) {
+ // the last page we found didn't have the 'last page' flag
+ // set. whoops!
+ break;
+ }
+ previous_safe = last_page_loc+1;
+ last_page_loc = stb_vorbis_get_file_offset(f);
+ }
+
+ set_file_offset(f, last_page_loc);
+
+ // parse the header
+ getn(f, (unsigned char *)header, 6);
+ // extract the absolute granule position
+ lo = get32(f);
+ hi = get32(f);
+ if (lo == 0xffffffff && hi == 0xffffffff) {
+ f->error = VORBIS_cant_find_last_page;
+ f->total_samples = SAMPLE_unknown;
+ goto done;
+ }
+ if (hi)
+ lo = 0xfffffffe; // saturate
+ f->total_samples = lo;
+
+ f->p_last.page_start = last_page_loc;
+ f->p_last.page_end = end;
+ f->p_last.last_decoded_sample = lo;
+
+ done:
+ set_file_offset(f, restore_offset);
+ }
+ return f->total_samples == SAMPLE_unknown ? 0 : f->total_samples;
+}
+
+float stb_vorbis_stream_length_in_seconds(stb_vorbis *f)
+{
+ return stb_vorbis_stream_length_in_samples(f) / (float) f->sample_rate;
+}
+
+
+
+int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output)
+{
+ int len, right,left,i;
+ if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
+
+ if (!vorbis_decode_packet(f, &len, &left, &right)) {
+ f->channel_buffer_start = f->channel_buffer_end = 0;
+ return 0;
+ }
+
+ len = vorbis_finish_frame(f, len, left, right);
+ for (i=0; i < f->channels; ++i)
+ f->outputs[i] = f->channel_buffers[i] + left;
+
+ f->channel_buffer_start = left;
+ f->channel_buffer_end = left+len;
+
+ if (channels) *channels = f->channels;
+ if (output) *output = f->outputs;
+ return len;
+}
+
+#ifndef STB_VORBIS_NO_STDIO
+
+stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length)
+{
+ stb_vorbis *f, p;
+ vorbis_init(&p, alloc);
+ p.f = file;
+ p.f_start = (uint32) ftell(file);
+ p.stream_len = length;
+ p.close_on_free = close_on_free;
+ if (start_decoder(&p)) {
+ f = vorbis_alloc(&p);
+ if (f) {
+ *f = p;
+ vorbis_pump_first_frame(f);
+ return f;
+ }
+ }
+ if (error) *error = p.error;
+ vorbis_deinit(&p);
+ return NULL;
+}
+
+stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc)
+{
+ unsigned int len, start;
+ start = (unsigned int) ftell(file);
+ fseek(file, 0, SEEK_END);
+ len = (unsigned int) (ftell(file) - start);
+ fseek(file, start, SEEK_SET);
+ return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len);
+}
+
+stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc)
+{
+ FILE *f = fopen(filename, "rb");
+ if (f)
+ return stb_vorbis_open_file(f, TRUE, error, alloc);
+ if (error) *error = VORBIS_file_open_failure;
+ return NULL;
+}
+#endif // STB_VORBIS_NO_STDIO
+
+stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc)
+{
+ stb_vorbis *f, p;
+ if (data == NULL) return NULL;
+ vorbis_init(&p, alloc);
+ p.stream = (uint8 *) data;
+ p.stream_end = (uint8 *) data + len;
+ p.stream_start = (uint8 *) p.stream;
+ p.stream_len = len;
+ p.push_mode = FALSE;
+ if (start_decoder(&p)) {
+ f = vorbis_alloc(&p);
+ if (f) {
+ *f = p;
+ vorbis_pump_first_frame(f);
+ return f;
+ }
+ }
+ if (error) *error = p.error;
+ vorbis_deinit(&p);
+ return NULL;
+}
+
+#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
+#define PLAYBACK_MONO 1
+#define PLAYBACK_LEFT 2
+#define PLAYBACK_RIGHT 4
+
+#define L (PLAYBACK_LEFT | PLAYBACK_MONO)
+#define C (PLAYBACK_LEFT | PLAYBACK_RIGHT | PLAYBACK_MONO)
+#define R (PLAYBACK_RIGHT | PLAYBACK_MONO)
+
+static int8 channel_position[7][6] =
+{
+ { 0 },
+ { C },
+ { L, R },
+ { L, C, R },
+ { L, R, L, R },
+ { L, C, R, L, R },
+ { L, C, R, L, R, C },
+};
+
+
+#ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT
+ typedef union {
+ float f;
+ int i;
+ } float_conv;
+ typedef char stb_vorbis_float_size_test[sizeof(float)==4 && sizeof(int) == 4];
+ #define FASTDEF(x) float_conv x
+ // add (1<<23) to convert to int, then divide by 2^SHIFT, then add 0.5/2^SHIFT to round
+ #define MAGIC(SHIFT) (1.5f * (1 << (23-SHIFT)) + 0.5f/(1 << SHIFT))
+ #define ADDEND(SHIFT) (((150-SHIFT) << 23) + (1 << 22))
+ #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) (temp.f = (x) + MAGIC(s), temp.i - ADDEND(s))
+ #define check_endianness()
+#else
+ #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) ((int) ((x) * (1 << (s))))
+ #define check_endianness()
+ #define FASTDEF(x)
+#endif
+
+static void copy_samples(short *dest, float *src, int len)
+{
+ int i;
+ check_endianness();
+ for (i=0; i < len; ++i) {
+ FASTDEF(temp);
+ int v = FAST_SCALED_FLOAT_TO_INT(temp, src[i],15);
+ if ((unsigned int) (v + 32768) > 65535)
+ v = v < 0 ? -32768 : 32767;
+ dest[i] = v;
+ }
+}
+
+static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len)
+{
+ #define BUFFER_SIZE 32
+ float buffer[BUFFER_SIZE];
+ int i,j,o,n = BUFFER_SIZE;
+ check_endianness();
+ for (o = 0; o < len; o += BUFFER_SIZE) {
+ memset(buffer, 0, sizeof(buffer));
+ if (o + n > len) n = len - o;
+ for (j=0; j < num_c; ++j) {
+ if (channel_position[num_c][j] & mask) {
+ for (i=0; i < n; ++i)
+ buffer[i] += data[j][d_offset+o+i];
+ }
+ }
+ for (i=0; i < n; ++i) {
+ FASTDEF(temp);
+ int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15);
+ if ((unsigned int) (v + 32768) > 65535)
+ v = v < 0 ? -32768 : 32767;
+ output[o+i] = v;
+ }
+ }
+}
+
+static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len)
+{
+ #define BUFFER_SIZE 32
+ float buffer[BUFFER_SIZE];
+ int i,j,o,n = BUFFER_SIZE >> 1;
+ // o is the offset in the source data
+ check_endianness();
+ for (o = 0; o < len; o += BUFFER_SIZE >> 1) {
+ // o2 is the offset in the output data
+ int o2 = o << 1;
+ memset(buffer, 0, sizeof(buffer));
+ if (o + n > len) n = len - o;
+ for (j=0; j < num_c; ++j) {
+ int m = channel_position[num_c][j] & (PLAYBACK_LEFT | PLAYBACK_RIGHT);
+ if (m == (PLAYBACK_LEFT | PLAYBACK_RIGHT)) {
+ for (i=0; i < n; ++i) {
+ buffer[i*2+0] += data[j][d_offset+o+i];
+ buffer[i*2+1] += data[j][d_offset+o+i];
+ }
+ } else if (m == PLAYBACK_LEFT) {
+ for (i=0; i < n; ++i) {
+ buffer[i*2+0] += data[j][d_offset+o+i];
+ }
+ } else if (m == PLAYBACK_RIGHT) {
+ for (i=0; i < n; ++i) {
+ buffer[i*2+1] += data[j][d_offset+o+i];
+ }
+ }
+ }
+ for (i=0; i < (n<<1); ++i) {
+ FASTDEF(temp);
+ int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15);
+ if ((unsigned int) (v + 32768) > 65535)
+ v = v < 0 ? -32768 : 32767;
+ output[o2+i] = v;
+ }
+ }
+}
+
+static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples)
+{
+ int i;
+ if (buf_c != data_c && buf_c <= 2 && data_c <= 6) {
+ static int channel_selector[3][2] = { {0}, {PLAYBACK_MONO}, {PLAYBACK_LEFT, PLAYBACK_RIGHT} };
+ for (i=0; i < buf_c; ++i)
+ compute_samples(channel_selector[buf_c][i], buffer[i]+b_offset, data_c, data, d_offset, samples);
+ } else {
+ int limit = buf_c < data_c ? buf_c : data_c;
+ for (i=0; i < limit; ++i)
+ copy_samples(buffer[i]+b_offset, data[i]+d_offset, samples);
+ for ( ; i < buf_c; ++i)
+ memset(buffer[i]+b_offset, 0, sizeof(short) * samples);
+ }
+}
+
+int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples)
+{
+ float **output;
+ int len = stb_vorbis_get_frame_float(f, NULL, &output);
+ if (len > num_samples) len = num_samples;
+ if (len)
+ convert_samples_short(num_c, buffer, 0, f->channels, output, 0, len);
+ return len;
+}
+
+static void convert_channels_short_interleaved(int buf_c, short *buffer, int data_c, float **data, int d_offset, int len)
+{
+ int i;
+ check_endianness();
+ if (buf_c != data_c && buf_c <= 2 && data_c <= 6) {
+ assert(buf_c == 2);
+ for (i=0; i < buf_c; ++i)
+ compute_stereo_samples(buffer, data_c, data, d_offset, len);
+ } else {
+ int limit = buf_c < data_c ? buf_c : data_c;
+ int j;
+ for (j=0; j < len; ++j) {
+ for (i=0; i < limit; ++i) {
+ FASTDEF(temp);
+ float f = data[i][d_offset+j];
+ int v = FAST_SCALED_FLOAT_TO_INT(temp, f,15);//data[i][d_offset+j],15);
+ if ((unsigned int) (v + 32768) > 65535)
+ v = v < 0 ? -32768 : 32767;
+ *buffer++ = v;
+ }
+ for ( ; i < buf_c; ++i)
+ *buffer++ = 0;
+ }
+ }
+}
+
+int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts)
+{
+ float **output;
+ int len;
+ if (num_c == 1) return stb_vorbis_get_frame_short(f,num_c,&buffer, num_shorts);
+ len = stb_vorbis_get_frame_float(f, NULL, &output);
+ if (len) {
+ if (len*num_c > num_shorts) len = num_shorts / num_c;
+ convert_channels_short_interleaved(num_c, buffer, f->channels, output, 0, len);
+ }
+ return len;
+}
+
+int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts)
+{
+ float **outputs;
+ int len = num_shorts / channels;
+ int n=0;
+ int z = f->channels;
+ if (z > channels) z = channels;
+ while (n < len) {
+ int k = f->channel_buffer_end - f->channel_buffer_start;
+ if (n+k >= len) k = len - n;
+ if (k)
+ convert_channels_short_interleaved(channels, buffer, f->channels, f->channel_buffers, f->channel_buffer_start, k);
+ buffer += k*channels;
+ n += k;
+ f->channel_buffer_start += k;
+ if (n == len) break;
+ if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break;
+ }
+ return n;
+}
+
+int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int len)
+{
+ float **outputs;
+ int n=0;
+ int z = f->channels;
+ if (z > channels) z = channels;
+ while (n < len) {
+ int k = f->channel_buffer_end - f->channel_buffer_start;
+ if (n+k >= len) k = len - n;
+ if (k)
+ convert_samples_short(channels, buffer, n, f->channels, f->channel_buffers, f->channel_buffer_start, k);
+ n += k;
+ f->channel_buffer_start += k;
+ if (n == len) break;
+ if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break;
+ }
+ return n;
+}
+
+#ifndef STB_VORBIS_NO_STDIO
+int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output)
+{
+ int data_len, offset, total, limit, error;
+ short *data;
+ stb_vorbis *v = stb_vorbis_open_filename(filename, &error, NULL);
+ if (v == NULL) return -1;
+ limit = v->channels * 4096;
+ *channels = v->channels;
+ if (sample_rate)
+ *sample_rate = v->sample_rate;
+ offset = data_len = 0;
+ total = limit;
+ data = (short *) malloc(total * sizeof(*data));
+ if (data == NULL) {
+ stb_vorbis_close(v);
+ return -2;
+ }
+ for (;;) {
+ int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data+offset, total-offset);
+ if (n == 0) break;
+ data_len += n;
+ offset += n * v->channels;
+ if (offset + limit > total) {
+ short *data2;
+ total *= 2;
+ data2 = (short *) realloc(data, total * sizeof(*data));
+ if (data2 == NULL) {
+ free(data);
+ stb_vorbis_close(v);
+ return -2;
+ }
+ data = data2;
+ }
+ }
+ *output = data;
+ stb_vorbis_close(v);
+ return data_len;
+}
+#endif // NO_STDIO
+
+int stb_vorbis_decode_memory(const uint8 *mem, int len, int *channels, int *sample_rate, short **output)
+{
+ int data_len, offset, total, limit, error;
+ short *data;
+ stb_vorbis *v = stb_vorbis_open_memory(mem, len, &error, NULL);
+ if (v == NULL) return -1;
+ limit = v->channels * 4096;
+ *channels = v->channels;
+ if (sample_rate)
+ *sample_rate = v->sample_rate;
+ offset = data_len = 0;
+ total = limit;
+ data = (short *) malloc(total * sizeof(*data));
+ if (data == NULL) {
+ stb_vorbis_close(v);
+ return -2;
+ }
+ for (;;) {
+ int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data+offset, total-offset);
+ if (n == 0) break;
+ data_len += n;
+ offset += n * v->channels;
+ if (offset + limit > total) {
+ short *data2;
+ total *= 2;
+ data2 = (short *) realloc(data, total * sizeof(*data));
+ if (data2 == NULL) {
+ free(data);
+ stb_vorbis_close(v);
+ return -2;
+ }
+ data = data2;
+ }
+ }
+ *output = data;
+ stb_vorbis_close(v);
+ return data_len;
+}
+#endif // STB_VORBIS_NO_INTEGER_CONVERSION
+
+int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats)
+{
+ float **outputs;
+ int len = num_floats / channels;
+ int n=0;
+ int z = f->channels;
+ if (z > channels) z = channels;
+ while (n < len) {
+ int i,j;
+ int k = f->channel_buffer_end - f->channel_buffer_start;
+ if (n+k >= len) k = len - n;
+ for (j=0; j < k; ++j) {
+ for (i=0; i < z; ++i)
+ *buffer++ = f->channel_buffers[i][f->channel_buffer_start+j];
+ for ( ; i < channels; ++i)
+ *buffer++ = 0;
+ }
+ n += k;
+ f->channel_buffer_start += k;
+ if (n == len)
+ break;
+ if (!stb_vorbis_get_frame_float(f, NULL, &outputs))
+ break;
+ }
+ return n;
+}
+
+int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples)
+{
+ float **outputs;
+ int n=0;
+ int z = f->channels;
+ if (z > channels) z = channels;
+ while (n < num_samples) {
+ int i;
+ int k = f->channel_buffer_end - f->channel_buffer_start;
+ if (n+k >= num_samples) k = num_samples - n;
+ if (k) {
+ for (i=0; i < z; ++i)
+ memcpy(buffer[i]+n, f->channel_buffers[i]+f->channel_buffer_start, sizeof(float)*k);
+ for ( ; i < channels; ++i)
+ memset(buffer[i]+n, 0, sizeof(float) * k);
+ }
+ n += k;
+ f->channel_buffer_start += k;
+ if (n == num_samples)
+ break;
+ if (!stb_vorbis_get_frame_float(f, NULL, &outputs))
+ break;
+ }
+ return n;
+}
+#endif // STB_VORBIS_NO_PULLDATA_API
+
+/* Version history
+ 1.09 - 2016/04/04 - back out 'avoid discarding last frame' fix from previous version
+ 1.08 - 2016/04/02 - fixed multiple warnings; fix setup memory leaks;
+ avoid discarding last frame of audio data
+ 1.07 - 2015/01/16 - fixed some warnings, fix mingw, const-correct API
+ some more crash fixes when out of memory or with corrupt files
+ 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson)
+ some crash fixes when out of memory or with corrupt files
+ 1.05 - 2015/04/19 - don't define __forceinline if it's redundant
+ 1.04 - 2014/08/27 - fix missing const-correct case in API
+ 1.03 - 2014/08/07 - Warning fixes
+ 1.02 - 2014/07/09 - Declare qsort compare function _cdecl on windows
+ 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float
+ 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in multichannel
+ (API change) report sample rate for decode-full-file funcs
+ 0.99996 - bracket #include <malloc.h> for macintosh compilation by Laurent Gomila
+ 0.99995 - use union instead of pointer-cast for fast-float-to-int to avoid alias-optimization problem
+ 0.99994 - change fast-float-to-int to work in single-precision FPU mode, remove endian-dependence
+ 0.99993 - remove assert that fired on legal files with empty tables
+ 0.99992 - rewind-to-start
+ 0.99991 - bugfix to stb_vorbis_get_samples_short by Bernhard Wodo
+ 0.9999 - (should have been 0.99990) fix no-CRT support, compiling as C++
+ 0.9998 - add a full-decode function with a memory source
+ 0.9997 - fix a bug in the read-from-FILE case in 0.9996 addition
+ 0.9996 - query length of vorbis stream in samples/seconds
+ 0.9995 - bugfix to another optimization that only happened in certain files
+ 0.9994 - bugfix to one of the optimizations that caused significant (but inaudible?) errors
+ 0.9993 - performance improvements; runs in 99% to 104% of time of reference implementation
+ 0.9992 - performance improvement of IMDCT; now performs close to reference implementation
+ 0.9991 - performance improvement of IMDCT
+ 0.999 - (should have been 0.9990) performance improvement of IMDCT
+ 0.998 - no-CRT support from Casey Muratori
+ 0.997 - bugfixes for bugs found by Terje Mathisen
+ 0.996 - bugfix: fast-huffman decode initialized incorrectly for sparse codebooks; fixing gives 10% speedup - found by Terje Mathisen
+ 0.995 - bugfix: fix to 'effective' overrun detection - found by Terje Mathisen
+ 0.994 - bugfix: garbage decode on final VQ symbol of a non-multiple - found by Terje Mathisen
+ 0.993 - bugfix: pushdata API required 1 extra byte for empty page (failed to consume final page if empty) - found by Terje Mathisen
+ 0.992 - fixes for MinGW warning
+ 0.991 - turn fast-float-conversion on by default
+ 0.990 - fix push-mode seek recovery if you seek into the headers
+ 0.98b - fix to bad release of 0.98
+ 0.98 - fix push-mode seek recovery; robustify float-to-int and support non-fast mode
+ 0.97 - builds under c++ (typecasting, don't use 'class' keyword)
+ 0.96 - somehow MY 0.95 was right, but the web one was wrong, so here's my 0.95 rereleased as 0.96, fixes a typo in the clamping code
+ 0.95 - clamping code for 16-bit functions
+ 0.94 - not publically released
+ 0.93 - fixed all-zero-floor case (was decoding garbage)
+ 0.92 - fixed a memory leak
+ 0.91 - conditional compiles to omit parts of the API and the infrastructure to support them: STB_VORBIS_NO_PULLDATA_API, STB_VORBIS_NO_PUSHDATA_API, STB_VORBIS_NO_STDIO, STB_VORBIS_NO_INTEGER_CONVERSION
+ 0.90 - first public release
+*/
+
+#endif // STB_VORBIS_HEADER_ONLY
diff --git a/src/external/stb_vorbis.h b/src/external/stb_vorbis.h
new file mode 100644
index 00000000..624ce4bc
--- /dev/null
+++ b/src/external/stb_vorbis.h
@@ -0,0 +1,393 @@
+// Ogg Vorbis audio decoder - v1.09 - public domain
+// http://nothings.org/stb_vorbis/
+//
+// Original version written by Sean Barrett in 2007.
+//
+// Originally sponsored by RAD Game Tools. Seeking sponsored
+// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software,
+// Aras Pranckevicius, and Sean Barrett.
+//
+// LICENSE
+//
+// This software is dual-licensed to the public domain and under the following
+// license: you are granted a perpetual, irrevocable license to copy, modify,
+// publish, and distribute this file as you see fit.
+//
+// No warranty for any purpose is expressed or implied by the author (nor
+// by RAD Game Tools). Report bugs and send enhancements to the author.
+//
+// Limitations:
+//
+// - floor 0 not supported (used in old ogg vorbis files pre-2004)
+// - lossless sample-truncation at beginning ignored
+// - cannot concatenate multiple vorbis streams
+// - sample positions are 32-bit, limiting seekable 192Khz
+// files to around 6 hours (Ogg supports 64-bit)
+//
+// Feature contributors:
+// Dougall Johnson (sample-exact seeking)
+//
+// Bugfix/warning contributors:
+// Terje Mathisen Niklas Frykholm Andy Hill
+// Casey Muratori John Bolton Gargaj
+// Laurent Gomila Marc LeBlanc Ronny Chevalier
+// Bernhard Wodo Evan Balster alxprd@github
+// Tom Beaumont Ingo Leitgeb Nicolas Guillemot
+// Phillip Bennefall Rohit Thiago Goulart
+// manxorist@github saga musix
+//
+// Partial history:
+// 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version
+// 1.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame
+// 1.07 - 2015/01/16 - fixes for crashes on invalid files; warning fixes; const
+// 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson)
+// some crash fixes when out of memory or with corrupt files
+// fix some inappropriately signed shifts
+// 1.05 - 2015/04/19 - don't define __forceinline if it's redundant
+// 1.04 - 2014/08/27 - fix missing const-correct case in API
+// 1.03 - 2014/08/07 - warning fixes
+// 1.02 - 2014/07/09 - declare qsort comparison as explicitly _cdecl in Windows
+// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct)
+// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
+// (API change) report sample rate for decode-full-file funcs
+//
+// See end of file for full version history.
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// HEADER BEGINS HERE
+//
+
+#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
+#define STB_VORBIS_INCLUDE_STB_VORBIS_H
+
+#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
+#define STB_VORBIS_NO_STDIO 1
+#endif
+
+#ifndef STB_VORBIS_NO_STDIO
+#include <stdio.h>
+#endif
+
+// NOTE: Added to work with raylib on Android
+#if defined(PLATFORM_ANDROID)
+ #include "utils.h" // Android fopen function map
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/////////// THREAD SAFETY
+
+// Individual stb_vorbis* handles are not thread-safe; you cannot decode from
+// them from multiple threads at the same time. However, you can have multiple
+// stb_vorbis* handles and decode from them independently in multiple thrads.
+
+
+/////////// MEMORY ALLOCATION
+
+// normally stb_vorbis uses malloc() to allocate memory at startup,
+// and alloca() to allocate temporary memory during a frame on the
+// stack. (Memory consumption will depend on the amount of setup
+// data in the file and how you set the compile flags for speed
+// vs. size. In my test files the maximal-size usage is ~150KB.)
+//
+// You can modify the wrapper functions in the source (setup_malloc,
+// setup_temp_malloc, temp_malloc) to change this behavior, or you
+// can use a simpler allocation model: you pass in a buffer from
+// which stb_vorbis will allocate _all_ its memory (including the
+// temp memory). "open" may fail with a VORBIS_outofmem if you
+// do not pass in enough data; there is no way to determine how
+// much you do need except to succeed (at which point you can
+// query get_info to find the exact amount required. yes I know
+// this is lame).
+//
+// If you pass in a non-NULL buffer of the type below, allocation
+// will occur from it as described above. Otherwise just pass NULL
+// to use malloc()/alloca()
+
+typedef struct
+{
+ char *alloc_buffer;
+ int alloc_buffer_length_in_bytes;
+} stb_vorbis_alloc;
+
+
+/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES
+
+typedef struct stb_vorbis stb_vorbis;
+
+typedef struct
+{
+ unsigned int sample_rate;
+ int channels;
+
+ unsigned int setup_memory_required;
+ unsigned int setup_temp_memory_required;
+ unsigned int temp_memory_required;
+
+ int max_frame_size;
+} stb_vorbis_info;
+
+// get general information about the file
+extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
+
+// get the last error detected (clears it, too)
+extern int stb_vorbis_get_error(stb_vorbis *f);
+
+// close an ogg vorbis file and free all memory in use
+extern void stb_vorbis_close(stb_vorbis *f);
+
+// this function returns the offset (in samples) from the beginning of the
+// file that will be returned by the next decode, if it is known, or -1
+// otherwise. after a flush_pushdata() call, this may take a while before
+// it becomes valid again.
+// NOT WORKING YET after a seek with PULLDATA API
+extern int stb_vorbis_get_sample_offset(stb_vorbis *f);
+
+// returns the current seek point within the file, or offset from the beginning
+// of the memory buffer. In pushdata mode it returns 0.
+extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
+
+/////////// PUSHDATA API
+
+#ifndef STB_VORBIS_NO_PUSHDATA_API
+
+// this API allows you to get blocks of data from any source and hand
+// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
+// you how much it used, and you have to give it the rest next time;
+// and stb_vorbis may not have enough data to work with and you will
+// need to give it the same data again PLUS more. Note that the Vorbis
+// specification does not bound the size of an individual frame.
+
+extern stb_vorbis *stb_vorbis_open_pushdata(
+ const unsigned char * datablock, int datablock_length_in_bytes,
+ int *datablock_memory_consumed_in_bytes,
+ int *error,
+ const stb_vorbis_alloc *alloc_buffer);
+// create a vorbis decoder by passing in the initial data block containing
+// the ogg&vorbis headers (you don't need to do parse them, just provide
+// the first N bytes of the file--you're told if it's not enough, see below)
+// on success, returns an stb_vorbis *, does not set error, returns the amount of
+// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
+// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
+// if returns NULL and *error is VORBIS_need_more_data, then the input block was
+// incomplete and you need to pass in a larger block from the start of the file
+
+extern int stb_vorbis_decode_frame_pushdata(
+ stb_vorbis *f,
+ const unsigned char *datablock, int datablock_length_in_bytes,
+ int *channels, // place to write number of float * buffers
+ float ***output, // place to write float ** array of float * buffers
+ int *samples // place to write number of output samples
+ );
+// decode a frame of audio sample data if possible from the passed-in data block
+//
+// return value: number of bytes we used from datablock
+//
+// possible cases:
+// 0 bytes used, 0 samples output (need more data)
+// N bytes used, 0 samples output (resynching the stream, keep going)
+// N bytes used, M samples output (one frame of data)
+// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
+// frame, because Vorbis always "discards" the first frame.
+//
+// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
+// instead only datablock_length_in_bytes-3 or less. This is because it wants
+// to avoid missing parts of a page header if they cross a datablock boundary,
+// without writing state-machiney code to record a partial detection.
+//
+// The number of channels returned are stored in *channels (which can be
+// NULL--it is always the same as the number of channels reported by
+// get_info). *output will contain an array of float* buffers, one per
+// channel. In other words, (*output)[0][0] contains the first sample from
+// the first channel, and (*output)[1][0] contains the first sample from
+// the second channel.
+
+extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
+// inform stb_vorbis that your next datablock will not be contiguous with
+// previous ones (e.g. you've seeked in the data); future attempts to decode
+// frames will cause stb_vorbis to resynchronize (as noted above), and
+// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it
+// will begin decoding the _next_ frame.
+//
+// if you want to seek using pushdata, you need to seek in your file, then
+// call stb_vorbis_flush_pushdata(), then start calling decoding, then once
+// decoding is returning you data, call stb_vorbis_get_sample_offset, and
+// if you don't like the result, seek your file again and repeat.
+#endif
+
+
+////////// PULLING INPUT API
+
+#ifndef STB_VORBIS_NO_PULLDATA_API
+// This API assumes stb_vorbis is allowed to pull data from a source--
+// either a block of memory containing the _entire_ vorbis stream, or a
+// FILE * that you or it create, or possibly some other reading mechanism
+// if you go modify the source to replace the FILE * case with some kind
+// of callback to your code. (But if you don't support seeking, you may
+// just want to go ahead and use pushdata.)
+
+#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
+extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output);
+#endif
+#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
+extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output);
+#endif
+// decode an entire file and output the data interleaved into a malloc()ed
+// buffer stored in *output. The return value is the number of samples
+// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
+// When you're done with it, just free() the pointer returned in *output.
+
+extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
+ int *error, const stb_vorbis_alloc *alloc_buffer);
+// create an ogg vorbis decoder from an ogg vorbis stream in memory (note
+// this must be the entire stream!). on failure, returns NULL and sets *error
+
+#ifndef STB_VORBIS_NO_STDIO
+extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
+ int *error, const stb_vorbis_alloc *alloc_buffer);
+// create an ogg vorbis decoder from a filename via fopen(). on failure,
+// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
+
+extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
+ int *error, const stb_vorbis_alloc *alloc_buffer);
+// create an ogg vorbis decoder from an open FILE *, looking for a stream at
+// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
+// note that stb_vorbis must "own" this stream; if you seek it in between
+// calls to stb_vorbis, it will become confused. Morever, if you attempt to
+// perform stb_vorbis_seek_*() operations on this file, it will assume it
+// owns the _entire_ rest of the file after the start point. Use the next
+// function, stb_vorbis_open_file_section(), to limit it.
+
+extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
+ int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len);
+// create an ogg vorbis decoder from an open FILE *, looking for a stream at
+// the _current_ seek point (ftell); the stream will be of length 'len' bytes.
+// on failure, returns NULL and sets *error. note that stb_vorbis must "own"
+// this stream; if you seek it in between calls to stb_vorbis, it will become
+// confused.
+#endif
+
+extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
+extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
+// these functions seek in the Vorbis file to (approximately) 'sample_number'.
+// after calling seek_frame(), the next call to get_frame_*() will include
+// the specified sample. after calling stb_vorbis_seek(), the next call to
+// stb_vorbis_get_samples_* will start with the specified sample. If you
+// do not need to seek to EXACTLY the target sample when using get_samples_*,
+// you can also use seek_frame().
+
+extern void stb_vorbis_seek_start(stb_vorbis *f);
+// this function is equivalent to stb_vorbis_seek(f,0)
+
+extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
+extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
+// these functions return the total length of the vorbis stream
+
+extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);
+// decode the next frame and return the number of samples. the number of
+// channels returned are stored in *channels (which can be NULL--it is always
+// the same as the number of channels reported by get_info). *output will
+// contain an array of float* buffers, one per channel. These outputs will
+// be overwritten on the next call to stb_vorbis_get_frame_*.
+//
+// You generally should not intermix calls to stb_vorbis_get_frame_*()
+// and stb_vorbis_get_samples_*(), since the latter calls the former.
+
+#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
+extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
+extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
+#endif
+// decode the next frame and return the number of *samples* per channel.
+// Note that for interleaved data, you pass in the number of shorts (the
+// size of your array), but the return value is the number of samples per
+// channel, not the total number of samples.
+//
+// The data is coerced to the number of channels you request according to the
+// channel coercion rules (see below). You must pass in the size of your
+// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
+// The maximum buffer size needed can be gotten from get_info(); however,
+// the Vorbis I specification implies an absolute maximum of 4096 samples
+// per channel.
+
+// Channel coercion rules:
+// Let M be the number of channels requested, and N the number of channels present,
+// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
+// and stereo R be the sum of all R and center channels (channel assignment from the
+// vorbis spec).
+// M N output
+// 1 k sum(Ck) for all k
+// 2 * stereo L, stereo R
+// k l k > l, the first l channels, then 0s
+// k l k <= l, the first k channels
+// Note that this is not _good_ surround etc. mixing at all! It's just so
+// you get something useful.
+
+extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);
+extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);
+// gets num_samples samples, not necessarily on a frame boundary--this requires
+// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.
+// Returns the number of samples stored per channel; it may be less than requested
+// at the end of the file. If there are no more samples in the file, returns 0.
+
+#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
+extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);
+extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);
+#endif
+// gets num_samples samples, not necessarily on a frame boundary--this requires
+// buffering so you have to supply the buffers. Applies the coercion rules above
+// to produce 'channels' channels. Returns the number of samples stored per channel;
+// it may be less than requested at the end of the file. If there are no more
+// samples in the file, returns 0.
+
+#endif
+
+//////// ERROR CODES
+
+enum STBVorbisError
+{
+ VORBIS__no_error,
+
+ VORBIS_need_more_data=1, // not a real error
+
+ VORBIS_invalid_api_mixing, // can't mix API modes
+ VORBIS_outofmem, // not enough memory
+ VORBIS_feature_not_supported, // uses floor 0
+ VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small
+ VORBIS_file_open_failure, // fopen() failed
+ VORBIS_seek_without_length, // can't seek in unknown-length file
+
+ VORBIS_unexpected_eof=10, // file is truncated?
+ VORBIS_seek_invalid, // seek past EOF
+
+ // decoding errors (corrupt/invalid stream) -- you probably
+ // don't care about the exact details of these
+
+ // vorbis errors:
+ VORBIS_invalid_setup=20,
+ VORBIS_invalid_stream,
+
+ // ogg errors:
+ VORBIS_missing_capture_pattern=30,
+ VORBIS_invalid_stream_structure_version,
+ VORBIS_continued_packet_flag_invalid,
+ VORBIS_incorrect_stream_serial_number,
+ VORBIS_invalid_first_page,
+ VORBIS_bad_packet_type,
+ VORBIS_cant_find_last_page,
+ VORBIS_seek_failed
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H
+//
+// HEADER ENDS HERE
+//
+////////////////////////////////////////////////////////////////////////////// \ No newline at end of file
diff --git a/src/external/tinfl.c b/src/external/tinfl.c
new file mode 100644
index 00000000..a17a156b
--- /dev/null
+++ b/src/external/tinfl.c
@@ -0,0 +1,592 @@
+/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c)
+ See "unlicense" statement at the end of this file.
+ Rich Geldreich <richgel99@gmail.com>, last updated May 20, 2011
+ Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
+
+ The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers.
+*/
+#ifndef TINFL_HEADER_INCLUDED
+#define TINFL_HEADER_INCLUDED
+
+#include <stdlib.h>
+
+typedef unsigned char mz_uint8;
+typedef signed short mz_int16;
+typedef unsigned short mz_uint16;
+typedef unsigned int mz_uint32;
+typedef unsigned int mz_uint;
+typedef unsigned long long mz_uint64;
+
+#if defined(_M_IX86) || defined(_M_X64)
+// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster).
+#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
+// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
+#define MINIZ_LITTLE_ENDIAN 1
+#endif
+
+#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
+// Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator)
+#define MINIZ_HAS_64BIT_REGISTERS 1
+#endif
+
+// Works around MSVC's spammy "warning C4127: conditional expression is constant" message.
+#ifdef _MSC_VER
+ #define MZ_MACRO_END while (0, 0)
+#else
+ #define MZ_MACRO_END while (0)
+#endif
+
+// Decompression flags used by tinfl_decompress().
+// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream.
+// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input.
+// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB).
+// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes.
+enum
+{
+ TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
+ TINFL_FLAG_HAS_MORE_INPUT = 2,
+ TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
+ TINFL_FLAG_COMPUTE_ADLER32 = 8
+};
+
+// High level decompression functions:
+// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc().
+// On entry:
+// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress.
+// On return:
+// Function returns a pointer to the decompressed data, or NULL on failure.
+// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data.
+// The caller must free() the returned block when it's no longer needed.
+void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
+
+// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory.
+// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success.
+#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
+size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
+
+// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer.
+// Returns 1 on success or 0 on failure.
+typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
+int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
+
+struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
+
+// Max size of LZ dictionary.
+#define TINFL_LZ_DICT_SIZE 32768
+
+// Return status.
+typedef enum
+{
+ TINFL_STATUS_BAD_PARAM = -3,
+ TINFL_STATUS_ADLER32_MISMATCH = -2,
+ TINFL_STATUS_FAILED = -1,
+ TINFL_STATUS_DONE = 0,
+ TINFL_STATUS_NEEDS_MORE_INPUT = 1,
+ TINFL_STATUS_HAS_MORE_OUTPUT = 2
+} tinfl_status;
+
+// Initializes the decompressor to its initial state.
+#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
+#define tinfl_get_adler32(r) (r)->m_check_adler32
+
+// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability.
+// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output.
+tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
+
+// Internal/private bits follow.
+enum
+{
+ TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
+ TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
+};
+
+typedef struct
+{
+ mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
+ mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
+} tinfl_huff_table;
+
+#if MINIZ_HAS_64BIT_REGISTERS
+ #define TINFL_USE_64BIT_BITBUF 1
+#endif
+
+#if TINFL_USE_64BIT_BITBUF
+ typedef mz_uint64 tinfl_bit_buf_t;
+ #define TINFL_BITBUF_SIZE (64)
+#else
+ typedef mz_uint32 tinfl_bit_buf_t;
+ #define TINFL_BITBUF_SIZE (32)
+#endif
+
+struct tinfl_decompressor_tag
+{
+ mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
+ tinfl_bit_buf_t m_bit_buf;
+ size_t m_dist_from_out_buf_start;
+ tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
+ mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
+};
+
+#endif // #ifdef TINFL_HEADER_INCLUDED
+
+// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.)
+
+#ifndef TINFL_HEADER_FILE_ONLY
+
+#include <string.h>
+
+// MZ_MALLOC, etc. are only used by the optional high-level helper functions.
+#ifdef MINIZ_NO_MALLOC
+ #define MZ_MALLOC(x) NULL
+ #define MZ_FREE(x) x, ((void)0)
+ #define MZ_REALLOC(p, x) NULL
+#else
+ #define MZ_MALLOC(x) malloc(x)
+ #define MZ_FREE(x) free(x)
+ #define MZ_REALLOC(p, x) realloc(p, x)
+#endif
+
+#define MZ_MAX(a,b) (((a)>(b))?(a):(b))
+#define MZ_MIN(a,b) (((a)<(b))?(a):(b))
+#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
+ #define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
+ #define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
+#else
+ #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
+ #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
+#endif
+
+#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
+#define TINFL_MEMSET(p, c, l) memset(p, c, l)
+
+#define TINFL_CR_BEGIN switch(r->m_state) { case 0:
+#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
+#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
+#define TINFL_CR_FINISH }
+
+// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never
+// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
+#define TINFL_GET_BYTE(state_index, c) do { \
+ if (pIn_buf_cur >= pIn_buf_end) { \
+ for ( ; ; ) { \
+ if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
+ TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
+ if (pIn_buf_cur < pIn_buf_end) { \
+ c = *pIn_buf_cur++; \
+ break; \
+ } \
+ } else { \
+ c = 0; \
+ break; \
+ } \
+ } \
+ } else c = *pIn_buf_cur++; } MZ_MACRO_END
+
+#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
+#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
+#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
+
+// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2.
+// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a
+// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the
+// bit buffer contains >=15 bits (deflate's max. Huffman code size).
+#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
+ do { \
+ temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
+ if (temp >= 0) { \
+ code_len = temp >> 9; \
+ if ((code_len) && (num_bits >= code_len)) \
+ break; \
+ } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
+ code_len = TINFL_FAST_LOOKUP_BITS; \
+ do { \
+ temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
+ } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
+ } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
+ } while (num_bits < 15);
+
+// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read
+// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully
+// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32.
+// The slow path is only executed at the very end of the input buffer.
+#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
+ int temp; mz_uint code_len, c; \
+ if (num_bits < 15) { \
+ if ((pIn_buf_end - pIn_buf_cur) < 2) { \
+ TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
+ } else { \
+ bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
+ } \
+ } \
+ if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
+ code_len = temp >> 9, temp &= 511; \
+ else { \
+ code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
+ } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
+
+tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
+{
+ static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
+ static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
+ static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
+ static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+ static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+ static const int s_min_table_sizes[3] = { 257, 1, 4 };
+
+ tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
+ const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
+ mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
+ size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
+
+ // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter).
+ if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
+
+ num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
+ TINFL_CR_BEGIN
+
+ bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
+ if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
+ {
+ TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
+ counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
+ if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
+ if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
+ }
+
+ do
+ {
+ TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
+ if (r->m_type == 0)
+ {
+ TINFL_SKIP_BITS(5, num_bits & 7);
+ for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
+ if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
+ while ((counter) && (num_bits))
+ {
+ TINFL_GET_BITS(51, dist, 8);
+ while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
+ *pOut_buf_cur++ = (mz_uint8)dist;
+ counter--;
+ }
+ while (counter)
+ {
+ size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
+ while (pIn_buf_cur >= pIn_buf_end)
+ {
+ if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
+ {
+ TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
+ }
+ else
+ {
+ TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
+ }
+ }
+ n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
+ TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
+ }
+ }
+ else if (r->m_type == 3)
+ {
+ TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
+ }
+ else
+ {
+ if (r->m_type == 1)
+ {
+ mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
+ r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
+ for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
+ }
+ else
+ {
+ for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
+ MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
+ r->m_table_sizes[2] = 19;
+ }
+ for ( ; (int)r->m_type >= 0; r->m_type--)
+ {
+ int tree_next, tree_cur; tinfl_huff_table *pTable;
+ mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
+ for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
+ used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
+ for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
+ if ((65536 != total) && (used_syms > 1))
+ {
+ TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
+ }
+ for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
+ {
+ mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
+ cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
+ if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
+ if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
+ rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
+ for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
+ {
+ tree_cur -= ((rev_code >>= 1) & 1);
+ if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
+ }
+ tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
+ }
+ if (r->m_type == 2)
+ {
+ for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
+ {
+ mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
+ if ((dist == 16) && (!counter))
+ {
+ TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
+ }
+ num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
+ TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
+ }
+ if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
+ {
+ TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
+ }
+ TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
+ }
+ }
+ for ( ; ; )
+ {
+ mz_uint8 *pSrc;
+ for ( ; ; )
+ {
+ if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
+ {
+ TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
+ if (counter >= 256)
+ break;
+ while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
+ *pOut_buf_cur++ = (mz_uint8)counter;
+ }
+ else
+ {
+ int sym2; mz_uint code_len;
+#if TINFL_USE_64BIT_BITBUF
+ if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
+#else
+ if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
+#endif
+ if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
+ code_len = sym2 >> 9;
+ else
+ {
+ code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
+ }
+ counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
+ if (counter & 256)
+ break;
+
+#if !TINFL_USE_64BIT_BITBUF
+ if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
+#endif
+ if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
+ code_len = sym2 >> 9;
+ else
+ {
+ code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
+ }
+ bit_buf >>= code_len; num_bits -= code_len;
+
+ pOut_buf_cur[0] = (mz_uint8)counter;
+ if (sym2 & 256)
+ {
+ pOut_buf_cur++;
+ counter = sym2;
+ break;
+ }
+ pOut_buf_cur[1] = (mz_uint8)sym2;
+ pOut_buf_cur += 2;
+ }
+ }
+ if ((counter &= 511) == 256) break;
+
+ num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
+ if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
+
+ TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
+ num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
+ if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
+
+ dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
+ if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
+ {
+ TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
+ }
+
+ pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
+
+ if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
+ {
+ while (counter--)
+ {
+ while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
+ *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
+ }
+ continue;
+ }
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
+ else if ((counter >= 9) && (counter <= dist))
+ {
+ const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
+ do
+ {
+ ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
+ ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
+ pOut_buf_cur += 8;
+ } while ((pSrc += 8) < pSrc_end);
+ if ((counter &= 7) < 3)
+ {
+ if (counter)
+ {
+ pOut_buf_cur[0] = pSrc[0];
+ if (counter > 1)
+ pOut_buf_cur[1] = pSrc[1];
+ pOut_buf_cur += counter;
+ }
+ continue;
+ }
+ }
+#endif
+ do
+ {
+ pOut_buf_cur[0] = pSrc[0];
+ pOut_buf_cur[1] = pSrc[1];
+ pOut_buf_cur[2] = pSrc[2];
+ pOut_buf_cur += 3; pSrc += 3;
+ } while ((int)(counter -= 3) > 2);
+ if ((int)counter > 0)
+ {
+ pOut_buf_cur[0] = pSrc[0];
+ if ((int)counter > 1)
+ pOut_buf_cur[1] = pSrc[1];
+ pOut_buf_cur += counter;
+ }
+ }
+ }
+ } while (!(r->m_final & 1));
+ if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
+ {
+ TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
+ }
+ TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
+ TINFL_CR_FINISH
+
+common_exit:
+ r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
+ *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
+ if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
+ {
+ const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
+ mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
+ while (buf_len)
+ {
+ for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
+ {
+ s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
+ s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
+ }
+ for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
+ s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
+ }
+ r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
+ }
+ return status;
+}
+
+// Higher level helper functions.
+void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
+{
+ tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0;
+ *pOut_len = 0;
+ tinfl_init(&decomp);
+ for ( ; ; )
+ {
+ size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
+ tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size,
+ (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
+ if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
+ {
+ MZ_FREE(pBuf); *pOut_len = 0; return NULL;
+ }
+ src_buf_ofs += src_buf_size;
+ *pOut_len += dst_buf_size;
+ if (status == TINFL_STATUS_DONE) break;
+ new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
+ pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
+ if (!pNew_buf)
+ {
+ MZ_FREE(pBuf); *pOut_len = 0; return NULL;
+ }
+ pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
+ }
+ return pBuf;
+}
+
+size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
+{
+ tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp);
+ status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
+ return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
+}
+
+int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
+{
+ int result = 0;
+ tinfl_decompressor decomp;
+ mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0;
+ if (!pDict)
+ return TINFL_STATUS_FAILED;
+ tinfl_init(&decomp);
+ for ( ; ; )
+ {
+ size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
+ tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
+ (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
+ in_buf_ofs += in_buf_size;
+ if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
+ break;
+ if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
+ {
+ result = (status == TINFL_STATUS_DONE);
+ break;
+ }
+ dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
+ }
+ MZ_FREE(pDict);
+ *pIn_buf_size = in_buf_ofs;
+ return result;
+}
+
+#endif // #ifndef TINFL_HEADER_FILE_ONLY
+
+/*
+ This is free and unencumbered software released into the public domain.
+
+ Anyone is free to copy, modify, publish, use, compile, sell, or
+ distribute this software, either in source code form or as a compiled
+ binary, for any purpose, commercial or non-commercial, and by any
+ means.
+
+ In jurisdictions that recognize copyright laws, the author or authors
+ of this software dedicate any and all copyright interest in the
+ software to the public domain. We make this dedication for the benefit
+ of the public at large and to the detriment of our heirs and
+ successors. We intend this dedication to be an overt act of
+ relinquishment in perpetuity of all present and future rights to this
+ software under copyright law.
+
+ 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 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.
+
+ For more information, please refer to <http://unlicense.org/>
+*/