woollybah пре 6 година
родитељ
комит
2be3e84fcb
54 измењених фајлова са 2033 додато и 1636 уклоњено
  1. 4 4
      bx.mod/bx.bmx
  2. 0 1
      bx.mod/bx/.appveyor.yml
  3. 1 0
      bx.mod/bx/.gitignore
  4. 8 6
      bx.mod/bx/3rdparty/ini/ini.h
  5. 7 11
      bx.mod/bx/include/bx/bx.h
  6. 3 4
      bx.mod/bx/include/bx/commandline.h
  7. 0 4
      bx.mod/bx/include/bx/easing.h
  8. 9 5
      bx.mod/bx/include/bx/filepath.h
  9. 7 1
      bx.mod/bx/include/bx/inline/bx.inl
  10. 4 0
      bx.mod/bx/include/bx/inline/easing.inl
  11. 411 251
      bx.mod/bx/include/bx/inline/math.inl
  12. 20 2
      bx.mod/bx/include/bx/inline/pixelformat.inl
  13. 13 50
      bx.mod/bx/include/bx/inline/readerwriter.inl
  14. 21 24
      bx.mod/bx/include/bx/inline/rng.inl
  15. 40 12
      bx.mod/bx/include/bx/inline/string.inl
  16. 199 308
      bx.mod/bx/include/bx/inline/uint32_t.inl
  17. 14 8
      bx.mod/bx/include/bx/macros.h
  18. 96 82
      bx.mod/bx/include/bx/math.h
  19. 5 7
      bx.mod/bx/include/bx/os.h
  20. 4 0
      bx.mod/bx/include/bx/pixelformat.h
  21. 71 71
      bx.mod/bx/include/bx/platform.h
  22. 7 7
      bx.mod/bx/include/bx/readerwriter.h
  23. 3 3
      bx.mod/bx/include/bx/rng.h
  24. 1 1
      bx.mod/bx/include/bx/settings.h
  25. 42 27
      bx.mod/bx/include/bx/string.h
  26. 79 129
      bx.mod/bx/include/bx/uint32_t.h
  27. 4 8
      bx.mod/bx/makefile
  28. 1 0
      bx.mod/bx/scripts/lemon.lua
  29. 63 65
      bx.mod/bx/scripts/toolchain.lua
  30. 2 2
      bx.mod/bx/src/bx.cpp
  31. 9 7
      bx.mod/bx/src/commandline.cpp
  32. 10 9
      bx.mod/bx/src/crtnone.cpp
  33. 0 2
      bx.mod/bx/src/debug.cpp
  34. 40 26
      bx.mod/bx/src/dtoa.cpp
  35. 2 2
      bx.mod/bx/src/file.cpp
  36. 37 33
      bx.mod/bx/src/filepath.cpp
  37. 56 104
      bx.mod/bx/src/math.cpp
  38. 49 37
      bx.mod/bx/src/os.cpp
  39. 3 4
      bx.mod/bx/src/settings.cpp
  40. 2 2
      bx.mod/bx/src/sort.cpp
  41. 178 128
      bx.mod/bx/src/string.cpp
  42. 0 2
      bx.mod/bx/src/timer.cpp
  43. 35 35
      bx.mod/bx/src/url.cpp
  44. 7 6
      bx.mod/bx/tests/easing_test.cpp
  45. 12 9
      bx.mod/bx/tests/math_bench.cpp
  46. 43 29
      bx.mod/bx/tests/math_test.cpp
  47. 195 0
      bx.mod/bx/tests/nlalloc_test.cpp
  48. 9 7
      bx.mod/bx/tests/rng_test.cpp
  49. 3 3
      bx.mod/bx/tests/settings_test.cpp
  50. 1 1
      bx.mod/bx/tests/simd_bench.cpp
  51. 131 56
      bx.mod/bx/tests/string_test.cpp
  52. 13 8
      bx.mod/bx/tests/uint32_test.cpp
  53. 42 32
      bx.mod/bx/tests/vsnprintf_test.cpp
  54. 17 1
      bx.mod/glue.cpp

+ 4 - 4
bx.mod/bx.bmx

@@ -38,16 +38,16 @@ ModuleInfo "History: 1.00"
 ModuleInfo "History: Initial Release."
 
 ?linuxx86
-ModuleInfo "CC_OPTS: -mfpmath=sse -msse2 -std=c++0x"
+ModuleInfo "CC_OPTS: -mfpmath=sse -msse2 -std=c++14"
 ?linuxx64
-ModuleInfo "CC_OPTS: -mfpmath=sse -msse2 -std=c++0x"
+ModuleInfo "CC_OPTS: -mfpmath=sse -msse2 -std=c++14"
 ?macos
 ModuleInfo "CC_OPTS: -msse2"
 ?win32
-ModuleInfo "CC_OPTS: -mfpmath=sse -msse2 -std=c++0x"
+ModuleInfo "CC_OPTS: -mfpmath=sse -msse2 -std=c++14"
 
 ?raspberrypi
-ModuleInfo "CC_OPTS: -std=c++0x"
+ModuleInfo "CC_OPTS: -std=c++14"
 ?
 
 ModuleInfo "CC_OPTS: -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS"

+ 0 - 1
bx.mod/bx/.appveyor.yml

@@ -5,7 +5,6 @@ os:
 
 environment:
   matrix:
-  - TOOLSET: vs2015
   - TOOLSET: vs2017
 
 configuration:

+ 1 - 0
bx.mod/bx/.gitignore

@@ -4,3 +4,4 @@
 .svn
 tags
 .DS_Store
+.gdb_history

+ 8 - 6
bx.mod/bx/3rdparty/ini/ini.h

@@ -496,7 +496,7 @@ ini_t* ini_create( void* memctx )
     }
 
 
-ini_t* ini_load( char const* data, void* memctx )
+ini_t* ini_load( char const* data, unsigned int len, void* memctx )
     {
     ini_t* ini;
     char const* ptr;
@@ -504,17 +504,19 @@ ini_t* ini_load( char const* data, void* memctx )
     char const* start;
     char const* start2;
     int l;
+    char const* end;
 
     ini = ini_create( memctx );
 
     ptr = data;
+    end = ptr + len;
     if( ptr )
         {
         s = 0;
-        while( *ptr )
+        while( ptr < end && *ptr )
             {
             /* trim leading whitespace */
-            while( *ptr && *ptr <=' ' )
+            while( ptr < end && *ptr && *ptr <=' ' )
                 ++ptr;
 
             /* done? */
@@ -544,17 +546,17 @@ ini_t* ini_load( char const* data, void* memctx )
             else
                 {
                 start = ptr;
-                while( *ptr && *ptr !='=' && *ptr != '\n' )
+                while( ptr < end && *ptr && *ptr !='=' && *ptr != '\n' )
                     ++ptr;
 
                 if( *ptr == '=' )
                     {
                     l = (int)( ptr - start);
                     ++ptr;
-                    while( *ptr && *ptr <= ' ' && *ptr != '\n' )
+                    while( ptr < end && *ptr && *ptr <= ' ' && *ptr != '\n' )
                         ptr++;
                     start2 = ptr;
-                    while( *ptr && *ptr != '\n' )
+                    while( ptr < end && *ptr && *ptr != '\n' )
                         ++ptr;
                     while( *(--ptr) <= ' ' )
                         (void)ptr;

+ 7 - 11
bx.mod/bx/include/bx/bx.h

@@ -17,7 +17,7 @@
 #include "macros.h"
 
 ///
-#define BX_COUNTOF(_x) sizeof(bx::COUNTOF_REQUIRES_ARRAY_ARGUMENT(_x) )
+#define BX_COUNTOF(_x) sizeof(bx::CountOfRequireArrayArgumentT(_x) )
 
 ///
 #define BX_IGNORE_C4127(_x) bx::ignoreC4127(!!(_x) )
@@ -27,8 +27,8 @@
 
 namespace bx
 {
-	const int32_t kExitSuccess = 0;
-	const int32_t kExitFailure = 1;
+	constexpr int32_t kExitSuccess = 0;
+	constexpr int32_t kExitFailure = 1;
 
 	/// Template for avoiding MSVC: C4127: conditional expression is constant
 	template<bool>
@@ -38,12 +38,12 @@ namespace bx
 	template<class Ty>
 	constexpr bool isTriviallyCopyable();
 
-	/// Exchange two values.
+	/// Swap two values.
 	template<typename Ty>
-	void xchg(Ty& _a, Ty& _b);
+	void swap(Ty& _a, Ty& _b);
 
-	/// Exchange memory.
-	void xchg(void* _a, void* _b, size_t _numBytes);
+	/// Swap memory.
+	void swap(void* _a, void* _b, size_t _numBytes);
 
 	/// Returns minimum of two values.
 	template<typename Ty>
@@ -73,10 +73,6 @@ namespace bx
 	template<typename Ty>
 	constexpr bool isPowerOf2(Ty _a);
 
-	// http://cnicholson.net/2011/01/stupid-c-tricks-a-better-sizeof_array/
-	template<typename T, size_t N>
-	char (&COUNTOF_REQUIRES_ARRAY_ARGUMENT(const T(&)[N]) )[N];
-
 	///
 	void memCopy(void* _dst, const void* _src, size_t _numBytes);
 

+ 3 - 4
bx.mod/bx/include/bx/commandline.h

@@ -6,13 +6,12 @@
 #ifndef BX_COMMANDLINE_H_HEADER_GUARD
 #define BX_COMMANDLINE_H_HEADER_GUARD
 
-#include "bx.h"
+#include "string.h"
 
 namespace bx
 {
-	/// Reference:
-	/// http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
-	const char* tokenizeCommandLine(const char* _commandLine, char* _buffer, uint32_t& _bufferSize, int32_t& _argc, char* _argv[], int32_t _maxArgvs, char _term = '\0');
+	///
+	StringView tokenizeCommandLine(const StringView& _commandLine, char* _buffer, uint32_t& _bufferSize, int32_t& _argc, char* _argv[], int32_t _maxArgvs, char _term = '\0');
 
 	///
 	class CommandLine

+ 0 - 4
bx.mod/bx/include/bx/easing.h

@@ -8,10 +8,6 @@
 
 #include "math.h"
 
-// Reference:
-// http://easings.net/
-// http://robertpenner.com/easing/
-
 namespace bx
 {
 	///

+ 9 - 5
bx.mod/bx/include/bx/filepath.h

@@ -14,7 +14,7 @@ BX_ERROR_RESULT(BX_ERROR_NOT_DIRECTORY, BX_MAKEFOURCC('b', 'x', 0, 1) );
 
 namespace bx
 {
-	const int32_t kMaxFilePath = 1024;
+	constexpr int32_t kMaxFilePath = 1024;
 
 	/// Special predefined OS directories.
 	///
@@ -85,19 +85,19 @@ namespace bx
 
 		/// If path is `/abv/gd/555/333/pod.mac` returns `/abv/gd/555/333/`.
 		///
-		const StringView getPath() const;
+		StringView getPath() const;
 
 		/// If path is `/abv/gd/555/333/pod.mac` returns `pod.mac`.
 		///
-		const StringView getFileName() const;
+		StringView getFileName() const;
 
 		/// If path is `/abv/gd/555/333/pod.mac` returns `pod`.
 		///
-		const StringView getBaseName() const;
+		StringView getBaseName() const;
 
 		/// If path is `/abv/gd/555/333/pod.mac` returns `.mac`.
 		///
-		const StringView getExt() const;
+		StringView getExt() const;
 
 		/// Returns true if file path is absolute.
 		///
@@ -112,15 +112,19 @@ namespace bx
 	};
 
 	/// Creates a directory named `_filePath`.
+	///
 	bool make(const FilePath& _filePath, Error* _err = NULL);
 
 	/// Creates a directory named `_filePath` along with all necessary parents.
+	///
 	bool makeAll(const FilePath& _filePath, Error* _err = NULL);
 
 	/// Removes file or directory.
+	///
 	bool remove(const FilePath& _filePath, Error* _err = NULL);
 
 	/// Removes file or directory recursivelly.
+	///
 	bool removeAll(const FilePath& _filePath, Error* _err = NULL);
 
 } // namespace bx

+ 7 - 1
bx.mod/bx/include/bx/inline/bx.inl

@@ -9,6 +9,12 @@
 
 namespace bx
 {
+	// Reference(S):
+	// - https://web.archive.org/web/20181115035420/http://cnicholson.net/2011/01/stupid-c-tricks-a-better-sizeof_array/
+	//
+	template<typename Ty, size_t Num>
+	char(&CountOfRequireArrayArgumentT(const Ty(&)[Num]))[Num];
+
 	template<bool>
 	inline constexpr bool isEnabled()
 	{
@@ -33,7 +39,7 @@ namespace bx
 	}
 
 	template<typename Ty>
-	inline void xchg(Ty& _a, Ty& _b)
+	inline void swap(Ty& _a, Ty& _b)
 	{
 		Ty tmp = _a; _a = _b; _b = tmp;
 	}

+ 4 - 0
bx.mod/bx/include/bx/inline/easing.inl

@@ -7,6 +7,10 @@
 #	error "Must be included from bx/easing.h!"
 #endif // BX_EASING_H_HEADER_GUARD
 
+ // Reference(s):
+ // - https://web.archive.org/web/20181126040153/https://easings.net/
+ // - https://web.archive.org/web/20181126040212/http://robertpenner.com/easing/
+ //
 namespace bx
 {
 	template<EaseFn ease>

+ 411 - 251
bx.mod/bx/include/bx/inline/math.inl

@@ -49,8 +49,9 @@ namespace bx
 
 	inline BX_CONST_FUNC uint32_t floatFlip(uint32_t _value)
 	{
-		// Reference:
-		// http://archive.fo/2012.12.08-212402/http://stereopsis.com/radix.html
+		// Reference(s):
+		// - http://archive.fo/2012.12.08-212402/http://stereopsis.com/radix.html
+		//
 		const uint32_t tmp0   = uint32_sra(_value, 31);
 		const uint32_t tmp1   = uint32_neg(tmp0);
 		const uint32_t mask   = uint32_or(tmp1, 0x80000000);
@@ -94,32 +95,48 @@ namespace bx
 		return tmp == UINT64_C(0x7ff0000000000000);
 	}
 
-	inline BX_CONST_FUNC float round(float _f)
+	inline BX_CONSTEXPR_FUNC float floor(float _a)
 	{
-		return floor(_f + 0.5f);
+		if (_a < 0.0f)
+		{
+			const float fr = fract(-_a);
+			const float result = -_a - fr;
+
+			return -(0.0f != fr
+				? result + 1.0f
+				: result)
+				;
+		}
+
+		return _a - fract(_a);
 	}
 
-	inline BX_CONST_FUNC float ceil(float _a)
+	inline BX_CONSTEXPR_FUNC float ceil(float _a)
 	{
 		return -floor(-_a);
 	}
 
-	inline BX_CONST_FUNC float lerp(float _a, float _b, float _t)
+	inline BX_CONSTEXPR_FUNC float round(float _f)
 	{
-		return _a + (_b - _a) * _t;
+		return floor(_f + 0.5f);
 	}
 
-	inline BX_CONST_FUNC float abs(float _a)
+	inline BX_CONSTEXPR_FUNC float lerp(float _a, float _b, float _t)
 	{
-		return _a < 0.0f ? -_a : _a;
+		return _a + (_b - _a) * _t;
 	}
 
-	inline BX_CONST_FUNC float sign(float _a)
+	inline BX_CONSTEXPR_FUNC float sign(float _a)
 	{
 		return _a < 0.0f ? -1.0f : 1.0f;
 	}
 
-	inline BX_CONST_FUNC float square(float _a)
+	inline BX_CONSTEXPR_FUNC float abs(float _a)
+	{
+		return _a < 0.0f ? -_a : _a;
+	}
+
+	inline BX_CONSTEXPR_FUNC float square(float _a)
 	{
 		return _a * _a;
 	}
@@ -237,17 +254,17 @@ namespace bx
 #endif // BX_CONFIG_SUPPORTS_SIMD
 	}
 
-	inline BX_CONST_FUNC float trunc(float _a)
+	inline BX_CONSTEXPR_FUNC float trunc(float _a)
 	{
 		return float(int(_a) );
 	}
 
-	inline BX_CONST_FUNC float fract(float _a)
+	inline BX_CONSTEXPR_FUNC float fract(float _a)
 	{
 		return _a - trunc(_a);
 	}
 
-	inline BX_CONST_FUNC float mad(float _a, float _b, float _c)
+	inline BX_CONSTEXPR_FUNC float mad(float _a, float _b, float _c)
 	{
 		return _a * _b + _c;
 	}
@@ -257,9 +274,11 @@ namespace bx
 		return _a - _b * floor(_a / _b);
 	}
 
-	inline BX_CONST_FUNC bool equal(float _a, float _b, float _epsilon)
+	inline BX_CONSTEXPR_FUNC bool equal(float _a, float _b, float _epsilon)
 	{
-		// http://realtimecollisiondetection.net/blog/?p=89
+		// Reference(s):
+		// - https://web.archive.org/web/20181103180318/http://realtimecollisiondetection.net/blog/?p=89
+		//
 		const float lhs = abs(_a - _b);
 		const float rhs = _epsilon * max(1.0f, abs(_a), abs(_b) );
 		return lhs <= rhs;
@@ -282,28 +301,33 @@ namespace bx
 		return result;
 	}
 
-	inline BX_CONST_FUNC float step(float _edge, float _a)
+	inline BX_CONSTEXPR_FUNC float step(float _edge, float _a)
 	{
 		return _a < _edge ? 0.0f : 1.0f;
 	}
 
-	inline BX_CONST_FUNC float pulse(float _a, float _start, float _end)
+	inline BX_CONSTEXPR_FUNC float pulse(float _a, float _start, float _end)
 	{
 		return step(_a, _start) - step(_a, _end);
 	}
 
-	inline BX_CONST_FUNC float smoothStep(float _a)
+	inline BX_CONSTEXPR_FUNC float smoothStep(float _a)
 	{
 		return square(_a)*(3.0f - 2.0f*_a);
 	}
 
-	inline BX_CONST_FUNC float bias(float _time, float _bias)
+	inline BX_CONSTEXPR_FUNC float bias(float _time, float _bias)
 	{
 		return _time / ( ( (1.0f/_bias - 2.0f)*(1.0f - _time) ) + 1.0f);
 	}
 
-	inline BX_CONST_FUNC float gain(float _time, float _gain)
+	inline BX_CONSTEXPR_FUNC float gain(float _time, float _gain)
 	{
+		// Reference(s):
+		// - Bias And Gain Are Your Friend
+		//   https://web.archive.org/web/20181126040535/https://blog.demofox.org/2012/09/24/bias-and-gain-are-your-friend/
+		//   https://web.archive.org/web/20181126040558/http://demofox.org/biasgain.html
+		//
 		if (_time < 0.5f)
 		{
 			return bias(_time * 2.0f, _gain) * 0.5f;
@@ -323,171 +347,233 @@ namespace bx
 		return _a + angleDiff(_a, _b) * _t;
 	}
 
-	inline void vec3Move(float* _result, const float* _a)
+	inline Vec3 load(const void* _ptr)
 	{
-		_result[0] = _a[0];
-		_result[1] = _a[1];
-		_result[2] = _a[2];
+		const float* ptr = reinterpret_cast<const float*>(_ptr);
+		return
+		{
+			ptr[0],
+			ptr[1],
+			ptr[2],
+		};
 	}
 
-	inline void vec3Abs(float* _result, const float* _a)
+	inline void store(void* _ptr, const Vec3 _a)
 	{
-		_result[0] = abs(_a[0]);
-		_result[1] = abs(_a[1]);
-		_result[2] = abs(_a[2]);
+		float* ptr = reinterpret_cast<float*>(_ptr);
+		ptr[0] = _a.x;
+		ptr[1] = _a.y;
+		ptr[2] = _a.z;
 	}
 
-	inline void vec3Neg(float* _result, const float* _a)
+	inline BX_CONSTEXPR_FUNC Vec3 abs(const Vec3 _a)
 	{
-		_result[0] = -_a[0];
-		_result[1] = -_a[1];
-		_result[2] = -_a[2];
+		return
+		{
+			abs(_a.x),
+			abs(_a.y),
+			abs(_a.z),
+		};
 	}
 
-	inline void vec3Add(float* _result, const float* _a, const float* _b)
+	inline BX_CONSTEXPR_FUNC Vec3 neg(const Vec3 _a)
 	{
-		_result[0] = _a[0] + _b[0];
-		_result[1] = _a[1] + _b[1];
-		_result[2] = _a[2] + _b[2];
+		return
+		{
+			-_a.x,
+			-_a.y,
+			-_a.z,
+		};
 	}
 
-	inline void vec3Add(float* _result, const float* _a, float _b)
+	inline BX_CONSTEXPR_FUNC Vec3 add(const Vec3 _a, const Vec3 _b)
 	{
-		_result[0] = _a[0] + _b;
-		_result[1] = _a[1] + _b;
-		_result[2] = _a[2] + _b;
+		return
+		{
+			_a.x + _b.x,
+			_a.y + _b.y,
+			_a.z + _b.z,
+		};
 	}
 
-	inline void vec3Sub(float* _result, const float* _a, const float* _b)
+	inline BX_CONSTEXPR_FUNC Vec3 add(const Vec3 _a, float _b)
 	{
-		_result[0] = _a[0] - _b[0];
-		_result[1] = _a[1] - _b[1];
-		_result[2] = _a[2] - _b[2];
+		return
+		{
+			_a.x + _b,
+			_a.y + _b,
+			_a.z + _b,
+		};
 	}
 
-	inline void vec3Sub(float* _result, const float* _a, float _b)
+	inline BX_CONSTEXPR_FUNC Vec3 sub(const Vec3 _a, const Vec3 _b)
 	{
-		_result[0] = _a[0] - _b;
-		_result[1] = _a[1] - _b;
-		_result[2] = _a[2] - _b;
+		return
+		{
+			_a.x - _b.x,
+			_a.y - _b.y,
+			_a.z - _b.z,
+		};
 	}
 
-	inline void vec3Mul(float* _result, const float* _a, const float* _b)
+	inline BX_CONSTEXPR_FUNC Vec3 sub(const Vec3 _a, float _b)
 	{
-		_result[0] = _a[0] * _b[0];
-		_result[1] = _a[1] * _b[1];
-		_result[2] = _a[2] * _b[2];
+		return
+		{
+			_a.x - _b,
+			_a.y - _b,
+			_a.z - _b,
+		};
 	}
 
-	inline void vec3Mul(float* _result, const float* _a, float _b)
+	inline BX_CONSTEXPR_FUNC Vec3 mul(const Vec3 _a, const Vec3 _b)
 	{
-		_result[0] = _a[0] * _b;
-		_result[1] = _a[1] * _b;
-		_result[2] = _a[2] * _b;
+		return
+		{
+			_a.x * _b.x,
+			_a.y * _b.y,
+			_a.z * _b.z,
+		};
 	}
 
-	inline float vec3Dot(const float* _a, const float* _b)
+	inline BX_CONSTEXPR_FUNC Vec3 mul(const Vec3 _a, float _b)
 	{
-		return _a[0]*_b[0] + _a[1]*_b[1] + _a[2]*_b[2];
+		return
+		{
+			_a.x * _b,
+			_a.y * _b,
+			_a.z * _b,
+		};
 	}
 
-	inline void vec3Cross(float* _result, const float* _a, const float* _b)
+	inline BX_CONSTEXPR_FUNC Vec3 mad(const Vec3 _a, const float _b, const Vec3 _c)
 	{
-		_result[0] = _a[1]*_b[2] - _a[2]*_b[1];
-		_result[1] = _a[2]*_b[0] - _a[0]*_b[2];
-		_result[2] = _a[0]*_b[1] - _a[1]*_b[0];
+		return add(mul(_a, _b), _c);
 	}
 
-	inline float vec3Length(const float* _a)
+	inline BX_CONSTEXPR_FUNC Vec3 mad(const Vec3 _a, const Vec3 _b, const Vec3 _c)
 	{
-		return sqrt(vec3Dot(_a, _a) );
+		return add(mul(_a, _b), _c);
 	}
 
-	inline void vec3Lerp(float* _result, const float* _a, const float* _b, float _t)
+	inline BX_CONSTEXPR_FUNC float dot(const Vec3 _a, const Vec3 _b)
 	{
-		_result[0] = lerp(_a[0], _b[0], _t);
-		_result[1] = lerp(_a[1], _b[1], _t);
-		_result[2] = lerp(_a[2], _b[2], _t);
+		return _a.x*_b.x + _a.y*_b.y + _a.z*_b.z;
 	}
 
-	inline void vec3Lerp(float* _result, const float* _a, const float* _b, const float* _c)
+	inline BX_CONSTEXPR_FUNC Vec3 cross(const Vec3 _a, const Vec3 _b)
 	{
-		_result[0] = lerp(_a[0], _b[0], _c[0]);
-		_result[1] = lerp(_a[1], _b[1], _c[1]);
-		_result[2] = lerp(_a[2], _b[2], _c[2]);
+		return
+		{
+			_a.y*_b.z - _a.z*_b.y,
+			_a.z*_b.x - _a.x*_b.z,
+			_a.x*_b.y - _a.y*_b.x,
+		};
 	}
 
-	inline float vec3Norm(float* _result, const float* _a)
+	inline BX_CONST_FUNC float length(const Vec3 _a)
 	{
-		const float len = vec3Length(_a);
-		const float invLen = 1.0f/len;
-		_result[0] = _a[0] * invLen;
-		_result[1] = _a[1] * invLen;
-		_result[2] = _a[2] * invLen;
-		return len;
+		return sqrt(dot(_a, _a) );
 	}
 
-	inline void vec3Min(float* _result, const float* _a, const float* _b)
+	inline BX_CONSTEXPR_FUNC Vec3 lerp(const Vec3 _a, const Vec3 _b, float _t)
 	{
-		_result[0] = min(_a[0], _b[0]);
-		_result[1] = min(_a[1], _b[1]);
-		_result[2] = min(_a[2], _b[2]);
+		return
+		{
+			lerp(_a.x, _b.x, _t),
+			lerp(_a.y, _b.y, _t),
+			lerp(_a.z, _b.z, _t),
+		};
 	}
 
-	inline void vec3Max(float* _result, const float* _a, const float* _b)
+	inline BX_CONSTEXPR_FUNC Vec3 lerp(const Vec3 _a, const Vec3 _b, const Vec3 _t)
 	{
-		_result[0] = max(_a[0], _b[0]);
-		_result[1] = max(_a[1], _b[1]);
-		_result[2] = max(_a[2], _b[2]);
+		return
+		{
+			lerp(_a.x, _b.x, _t.x),
+			lerp(_a.y, _b.y, _t.y),
+			lerp(_a.z, _b.z, _t.z),
+		};
 	}
 
-	inline void vec3Rcp(float* _result, const float* _a)
+	inline BX_CONST_FUNC Vec3 normalize(const Vec3 _a)
 	{
-		_result[0] = 1.0f / _a[0];
-		_result[1] = 1.0f / _a[1];
-		_result[2] = 1.0f / _a[2];
+		const float invLen = 1.0f/length(_a);
+		const Vec3 result = mul(_a, invLen);
+		return result;
 	}
 
-	inline void vec3TangentFrame(const float* _n, float* _t, float* _b)
+	inline BX_CONSTEXPR_FUNC Vec3 min(const Vec3 _a, const Vec3 _b)
 	{
-		const float nx = _n[0];
-		const float ny = _n[1];
-		const float nz = _n[2];
+		return
+		{
+			min(_a.x, _b.x),
+			min(_a.y, _b.y),
+			min(_a.z, _b.z),
+		};
+	}
+
+	inline BX_CONSTEXPR_FUNC Vec3 max(const Vec3 _a, const Vec3 _b)
+	{
+		return
+		{
+			max(_a.x, _b.x),
+			max(_a.y, _b.y),
+			max(_a.z, _b.z),
+		};
+	}
+
+	inline BX_CONSTEXPR_FUNC Vec3 rcp(const Vec3 _a)
+	{
+		return
+		{
+			1.0f / _a.x,
+			1.0f / _a.y,
+			1.0f / _a.z,
+		};
+	}
+
+	inline void calcTangentFrame(Vec3& _outT, Vec3& _outB, const Vec3 _n)
+	{
+		const float nx = _n.x;
+		const float ny = _n.y;
+		const float nz = _n.z;
 
 		if (abs(nx) > abs(nz) )
 		{
 			float invLen = 1.0f / sqrt(nx*nx + nz*nz);
-			_t[0] = -nz * invLen;
-			_t[1] =  0.0f;
-			_t[2] =  nx * invLen;
+			_outT.x = -nz * invLen;
+			_outT.y =  0.0f;
+			_outT.z =  nx * invLen;
 		}
 		else
 		{
 			float invLen = 1.0f / sqrt(ny*ny + nz*nz);
-			_t[0] =  0.0f;
-			_t[1] =  nz * invLen;
-			_t[2] = -ny * invLen;
+			_outT.x =  0.0f;
+			_outT.y =  nz * invLen;
+			_outT.z = -ny * invLen;
 		}
 
-		vec3Cross(_b, _n, _t);
+		_outB = cross(_n, _outT);
 	}
 
-	inline void vec3TangentFrame(const float* _n, float* _t, float* _b, float _angle)
+	inline void calcTangentFrame(Vec3& _outT, Vec3& _outB, const Vec3 _n, float _angle)
 	{
-		vec3TangentFrame(_n, _t, _b);
+		calcTangentFrame(_outT, _outB, _n);
 
 		const float sa = sin(_angle);
 		const float ca = cos(_angle);
 
-		_t[0] = -sa * _b[0] + ca * _t[0];
-		_t[1] = -sa * _b[1] + ca * _t[1];
-		_t[2] = -sa * _b[2] + ca * _t[2];
+		_outT.x = -sa * _outB.x + ca * _outT.x;
+		_outT.y = -sa * _outB.y + ca * _outT.y;
+		_outT.z = -sa * _outB.z + ca * _outT.z;
 
-		vec3Cross(_b, _n, _t);
+		_outB = cross(_n, _outT);
 	}
 
-	inline void vec3FromLatLong(float* _vec, float _u, float _v)
+	inline BX_CONST_FUNC Vec3 fromLatLong(float _u, float _v)
 	{
+		Vec3 result;
 		const float phi   = _u * kPi2;
 		const float theta = _v * kPi;
 
@@ -496,180 +582,214 @@ namespace bx
 		const float ct = cos(theta);
 		const float cp = cos(phi);
 
-		_vec[0] = -st*sp;
-		_vec[1] =  ct;
-		_vec[2] = -st*cp;
+		result.x = -st*sp;
+		result.y =  ct;
+		result.z = -st*cp;
+		return result;
 	}
 
-	inline void vec3ToLatLong(float* _outU, float* _outV, const float* _dir)
+	inline void toLatLong(float* _outU, float* _outV, const Vec3 _dir)
 	{
-		const float phi   = atan2(_dir[0], _dir[2]);
-		const float theta = acos(_dir[1]);
+		const float phi   = atan2(_dir.x, _dir.z);
+		const float theta = acos(_dir.y);
 
 		*_outU = (bx::kPi + phi)/bx::kPi2;
 		*_outV = theta*bx::kInvPi;
 	}
 
-	inline void quatIdentity(float* _result)
+	inline BX_CONSTEXPR_FUNC Quaternion invert(const Quaternion _a)
 	{
-		_result[0] = 0.0f;
-		_result[1] = 0.0f;
-		_result[2] = 0.0f;
-		_result[3] = 1.0f;
+		return
+		{
+			-_a.x,
+			-_a.y,
+			-_a.z,
+			 _a.w,
+		};
 	}
 
-	inline void quatMove(float* _result, const float* _a)
+	inline BX_CONSTEXPR_FUNC Vec3 mulXyz(const Quaternion _a, const Quaternion _b)
 	{
-		_result[0] = _a[0];
-		_result[1] = _a[1];
-		_result[2] = _a[2];
-		_result[3] = _a[3];
+		const float ax = _a.x;
+		const float ay = _a.y;
+		const float az = _a.z;
+		const float aw = _a.w;
+
+		const float bx = _b.x;
+		const float by = _b.y;
+		const float bz = _b.z;
+		const float bw = _b.w;
+
+		return
+		{
+			aw * bx + ax * bw + ay * bz - az * by,
+			aw * by - ax * bz + ay * bw + az * bx,
+			aw * bz + ax * by - ay * bx + az * bw,
+		};
 	}
 
-	inline void quatMulXYZ(float* _result, const float* _qa, const float* _qb)
+	inline BX_CONSTEXPR_FUNC Quaternion mul(const Quaternion _a, const Quaternion _b)
 	{
-		const float ax = _qa[0];
-		const float ay = _qa[1];
-		const float az = _qa[2];
-		const float aw = _qa[3];
+		const float ax = _a.x;
+		const float ay = _a.y;
+		const float az = _a.z;
+		const float aw = _a.w;
 
-		const float bx = _qb[0];
-		const float by = _qb[1];
-		const float bz = _qb[2];
-		const float bw = _qb[3];
+		const float bx = _b.x;
+		const float by = _b.y;
+		const float bz = _b.z;
+		const float bw = _b.w;
 
-		_result[0] = aw * bx + ax * bw + ay * bz - az * by;
-		_result[1] = aw * by - ax * bz + ay * bw + az * bx;
-		_result[2] = aw * bz + ax * by - ay * bx + az * bw;
+		return
+		{
+			aw * bx + ax * bw + ay * bz - az * by,
+			aw * by - ax * bz + ay * bw + az * bx,
+			aw * bz + ax * by - ay * bx + az * bw,
+			aw * bw - ax * bx - ay * by - az * bz,
+		};
 	}
 
-	inline void quatMul(float* _result, const float* _qa, const float* _qb)
+	namespace detail
 	{
-		const float ax = _qa[0];
-		const float ay = _qa[1];
-		const float az = _qa[2];
-		const float aw = _qa[3];
-
-		const float bx = _qb[0];
-		const float by = _qb[1];
-		const float bz = _qb[2];
-		const float bw = _qb[3];
-
-		_result[0] = aw * bx + ax * bw + ay * bz - az * by;
-		_result[1] = aw * by - ax * bz + ay * bw + az * bx;
-		_result[2] = aw * bz + ax * by - ay * bx + az * bw;
-		_result[3] = aw * bw - ax * bx - ay * by - az * bz;
+		inline BX_CONSTEXPR_FUNC Quaternion loadQ(const Vec3 _v)
+		{
+			return { _v.x, _v.y, _v.z, 0.0f };
+		}
 	}
 
-	inline void quatInvert(float* _result, const float* _quat)
+	inline BX_CONSTEXPR_FUNC Vec3 mul(const Vec3 _v, const Quaternion _q)
 	{
-		_result[0] = -_quat[0];
-		_result[1] = -_quat[1];
-		_result[2] = -_quat[2];
-		_result[3] =  _quat[3];
+		const Quaternion tmp0 = invert(_q);
+		const Quaternion qv   = detail::loadQ(_v);
+		const Quaternion tmp1 = mul(tmp0, qv);
+		const Vec3 result     = mulXyz(tmp1, _q);
+
+		return result;
 	}
 
-	inline float quatDot(const float* _a, const float* _b)
+	inline BX_CONSTEXPR_FUNC float dot(const Quaternion _a, const Quaternion _b)
 	{
-		return _a[0]*_b[0]
-			 + _a[1]*_b[1]
-			 + _a[2]*_b[2]
-			 + _a[3]*_b[3]
-			 ;
+		return
+			  _a.x * _b.x
+			+ _a.y * _b.y
+			+ _a.z * _b.z
+			+ _a.w * _b.w
+			;
 	}
 
-	inline void quatNorm(float* _result, const float* _quat)
+	inline BX_CONSTEXPR_FUNC Quaternion normalize(const Quaternion _a)
 	{
-		const float norm = quatDot(_quat, _quat);
+		const float norm = dot(_a, _a);
 		if (0.0f < norm)
 		{
 			const float invNorm = 1.0f / sqrt(norm);
-			_result[0] = _quat[0] * invNorm;
-			_result[1] = _quat[1] * invNorm;
-			_result[2] = _quat[2] * invNorm;
-			_result[3] = _quat[3] * invNorm;
+
+			return
+			{
+				_a.x * invNorm,
+				_a.y * invNorm,
+				_a.z * invNorm,
+				_a.w * invNorm,
+			};
 		}
-		else
+
+		return
 		{
-			quatIdentity(_result);
-		}
+			0.0f,
+			0.0f,
+			0.0f,
+			1.0f,
+		};
 	}
 
-	inline void quatToEuler(float* _result, const float* _quat)
+	inline BX_CONST_FUNC Vec3 toEuler(const Quaternion _a)
 	{
-		const float x = _quat[0];
-		const float y = _quat[1];
-		const float z = _quat[2];
-		const float w = _quat[3];
+		const float xx  = _a.x;
+		const float yy  = _a.y;
+		const float zz  = _a.z;
+		const float ww  = _a.w;
+		const float xsq = square(xx);
+		const float ysq = square(yy);
+		const float zsq = square(zz);
 
-		const float yy = y * y;
-		const float zz = z * z;
-
-		const float xx = x * x;
-		_result[0] = atan2(2.0f * (x * w - y * z), 1.0f - 2.0f * (xx + zz) );
-		_result[1] = atan2(2.0f * (y * w + x * z), 1.0f - 2.0f * (yy + zz) );
-		_result[2] = asin (2.0f * (x * y + z * w) );
+		return
+		{
+			atan2(2.0f * (xx * ww - yy * zz), 1.0f - 2.0f * (xsq + zsq) ),
+			atan2(2.0f * (yy * ww + xx * zz), 1.0f - 2.0f * (ysq + zsq) ),
+			asin( 2.0f * (xx * yy + zz * ww) ),
+		};
 	}
 
-	inline void quatRotateAxis(float* _result, const float* _axis, float _angle)
+	inline BX_CONST_FUNC Quaternion rotateAxis(const Vec3 _axis, float _angle)
 	{
 		const float ha = _angle * 0.5f;
-		const float ca = cos(ha);
 		const float sa = sin(ha);
-		_result[0] = _axis[0] * sa;
-		_result[1] = _axis[1] * sa;
-		_result[2] = _axis[2] * sa;
-		_result[3] = ca;
+
+		return
+		{
+			_axis.x * sa,
+			_axis.y * sa,
+			_axis.z * sa,
+			cos(ha),
+		};
 	}
 
-	inline void quatRotateX(float* _result, float _ax)
+	inline BX_CONST_FUNC Quaternion rotateX(float _ax)
 	{
 		const float hx = _ax * 0.5f;
-		const float cx = cos(hx);
-		const float sx = sin(hx);
-		_result[0] = sx;
-		_result[1] = 0.0f;
-		_result[2] = 0.0f;
-		_result[3] = cx;
+
+		return
+		{
+			sin(hx),
+			0.0f,
+			0.0f,
+			cos(hx),
+		};
 	}
 
-	inline void quatRotateY(float* _result, float _ay)
+	inline BX_CONST_FUNC Quaternion rotateY(float _ay)
 	{
 		const float hy = _ay * 0.5f;
-		const float cy = cos(hy);
-		const float sy = sin(hy);
-		_result[0] = 0.0f;
-		_result[1] = sy;
-		_result[2] = 0.0f;
-		_result[3] = cy;
+
+		return
+		{
+			0.0f,
+			sin(hy),
+			0.0f,
+			cos(hy),
+		};
 	}
 
-	inline void quatRotateZ(float* _result, float _az)
+	inline BX_CONST_FUNC Quaternion rotateZ(float _az)
 	{
 		const float hz = _az * 0.5f;
-		const float cz = cos(hz);
-		const float sz = sin(hz);
-		_result[0] = 0.0f;
-		_result[1] = 0.0f;
-		_result[2] = sz;
-		_result[3] = cz;
+
+		return
+		{
+			0.0f,
+			0.0f,
+			sin(hz),
+			cos(hz),
+		};
 	}
 
-	inline void vec3MulQuat(float* _result, const float* _vec, const float* _quat)
+	inline void vec3Add(float* _result, const float* _a, const float* _b)
 	{
-		float tmp0[4];
-		quatInvert(tmp0, _quat);
-
-		float qv[4];
-		qv[0] = _vec[0];
-		qv[1] = _vec[1];
-		qv[2] = _vec[2];
-		qv[3] = 0.0f;
+		_result[0] = _a[0] + _b[0];
+		_result[1] = _a[1] + _b[1];
+		_result[2] = _a[2] + _b[2];
+	}
 
-		float tmp1[4];
-		quatMul(tmp1, tmp0, qv);
+	inline void vec3Sub(float* _result, const float* _a, const float* _b)
+	{
+		_result[0] = _a[0] - _b[0];
+		_result[1] = _a[1] - _b[1];
+		_result[2] = _a[2] - _b[2];
+	}
 
-		quatMulXYZ(_result, tmp1, _quat);
+	inline float vec3Dot(const float* _a, const float* _b)
+	{
+		return _a[0]*_b[0] + _a[1]*_b[1] + _a[2]*_b[2];
 	}
 
 	inline void mtxIdentity(float* _result)
@@ -702,13 +822,14 @@ namespace bx
 
 	inline void mtxFromNormal(float* _result, const float* _normal, float _scale, const float* _pos)
 	{
-		float tangent[3];
-		float bitangent[3];
-		vec3TangentFrame(_normal, tangent, bitangent);
+		const bx::Vec3 normal = bx::load(_normal);
+		bx::Vec3 tangent;
+		bx::Vec3 bitangent;
+		calcTangentFrame(tangent, bitangent, normal);
 
-		vec3Mul(&_result[ 0], bitangent, _scale);
-		vec3Mul(&_result[ 4], _normal,   _scale);
-		vec3Mul(&_result[ 8], tangent,   _scale);
+		store(&_result[ 0], mul(bitangent, _scale) );
+		store(&_result[ 4], mul(normal,    _scale) );
+		store(&_result[ 8], mul(tangent,   _scale) );
 
 		_result[ 3] = 0.0f;
 		_result[ 7] = 0.0f;
@@ -721,13 +842,14 @@ namespace bx
 
 	inline void mtxFromNormal(float* _result, const float* _normal, float _scale, const float* _pos, float _angle)
 	{
-		float tangent[3];
-		float bitangent[3];
-		vec3TangentFrame(_normal, tangent, bitangent, _angle);
+		const bx::Vec3 normal = bx::load(_normal);
+		bx::Vec3 tangent;
+		bx::Vec3 bitangent;
+		calcTangentFrame(tangent, bitangent, normal, _angle);
 
-		vec3Mul(&_result[ 0], bitangent, _scale);
-		vec3Mul(&_result[ 4], _normal,   _scale);
-		vec3Mul(&_result[ 8], tangent,   _scale);
+		store(&_result[0], mul(bitangent, _scale) );
+		store(&_result[4], mul(normal,    _scale) );
+		store(&_result[8], mul(tangent,   _scale) );
 
 		_result[ 3] = 0.0f;
 		_result[ 7] = 0.0f;
@@ -797,6 +919,42 @@ namespace bx
 		mtxQuatTranslation(_result, quat, _translation);
 	}
 
+	inline Vec3 mul(const Vec3 _vec, const float* _mat)
+	{
+		Vec3 result;
+		result.x = _vec.x * _mat[0] + _vec.y * _mat[4] + _vec.z * _mat[ 8] + _mat[12];
+		result.y = _vec.x * _mat[1] + _vec.y * _mat[5] + _vec.z * _mat[ 9] + _mat[13];
+		result.z = _vec.x * _mat[2] + _vec.y * _mat[6] + _vec.z * _mat[10] + _mat[14];
+		return result;
+	}
+
+	inline Vec3 mulXyz0(const Vec3 _vec, const float* _mat)
+	{
+		Vec3 result;
+		result.x = _vec.x * _mat[0] + _vec.y * _mat[4] + _vec.z * _mat[ 8];
+		result.y = _vec.x * _mat[1] + _vec.y * _mat[5] + _vec.z * _mat[ 9];
+		result.z = _vec.x * _mat[2] + _vec.y * _mat[6] + _vec.z * _mat[10];
+		return result;
+	}
+
+	inline Vec3 mulH(const Vec3 _vec, const float* _mat)
+	{
+		const float xx   = _vec.x * _mat[0] + _vec.y * _mat[4] + _vec.z * _mat[ 8] + _mat[12];
+		const float yy   = _vec.x * _mat[1] + _vec.y * _mat[5] + _vec.z * _mat[ 9] + _mat[13];
+		const float zz   = _vec.x * _mat[2] + _vec.y * _mat[6] + _vec.z * _mat[10] + _mat[14];
+		const float ww   = _vec.x * _mat[3] + _vec.y * _mat[7] + _vec.z * _mat[11] + _mat[15];
+		const float invW = sign(ww) / ww;
+
+		Vec3 result =
+		{
+			xx * invW,
+			yy * invW,
+			zz * invW,
+		};
+
+		return result;
+	}
+
 	inline void vec3MulMtx(float* _result, const float* _vec, const float* _mat)
 	{
 		_result[0] = _vec[0] * _mat[ 0] + _vec[1] * _mat[4] + _vec[2] * _mat[ 8] + _mat[12];
@@ -917,29 +1075,31 @@ namespace bx
 		_dst[15] =  _src[15];
 	}
 
-	inline void calcNormal(float _result[3], float _va[3], float _vb[3], float _vc[3])
+	inline void calcNormal(float _result[3], const float _va[3], const float _vb[3], const float _vc[3])
 	{
-		float ba[3];
-		vec3Sub(ba, _vb, _va);
-
-		float ca[3];
-		vec3Sub(ca, _vc, _va);
+		const bx::Vec3 va    = bx::load(_va);
+		const bx::Vec3 vb    = bx::load(_vb);
+		const bx::Vec3 vc    = bx::load(_vc);
+		const bx::Vec3 ba    = bx::sub(vb, va);
+		const bx::Vec3 ca    = bx::sub(vc, va);
+		const bx::Vec3 baxca = bx::cross(ba, ca);
 
-		float baxca[3];
-		vec3Cross(baxca, ba, ca);
-
-		vec3Norm(_result, baxca);
+		bx::store(_result, bx::normalize(baxca) );
 	}
 
-	inline void calcPlane(float _result[4], float _va[3], float _vb[3], float _vc[3])
+	inline void calcPlane(float _result[4], const float _va[3], const float _vb[3], const float _vc[3])
 	{
 		float normal[3];
 		calcNormal(normal, _va, _vb, _vc);
+		calcPlane(_result, normal, _va);
+	}
 
-		_result[0] = normal[0];
-		_result[1] = normal[1];
-		_result[2] = normal[2];
-		_result[3] = -vec3Dot(normal, _va);
+	inline void calcPlane(float _result[4], const float _normal[3], const float _pos[3])
+	{
+		_result[0] = _normal[0];
+		_result[1] = _normal[1];
+		_result[2] = _normal[2];
+		_result[3] = -dot(bx::load(_normal), bx::load(_pos) );
 	}
 
 	inline BX_CONST_FUNC float toLinear(float _a)

+ 20 - 2
bx.mod/bx/include/bx/inline/pixelformat.inl

@@ -31,6 +31,23 @@ namespace bx
 		return max(-1.0f, float(_value) / _scale);
 	}
 
+	// A8
+	inline void packA8(void* _dst, const float* _src)
+	{
+		uint8_t* dst = (uint8_t*)_dst;
+		dst[0] = uint8_t(toUnorm(_src[3], 255.0f) );
+	}
+
+	inline void unpackA8(float* _dst, const void* _src)
+	{
+		const uint8_t* src = (const uint8_t*)_src;
+		const float aa = fromUnorm(src[0], 255.0f);
+		_dst[0] = aa;
+		_dst[1] = aa;
+		_dst[2] = aa;
+		_dst[3] = aa;
+	}
+
 	// R8
 	inline void packR8(void* _dst, const float* _src)
 	{
@@ -707,8 +724,9 @@ namespace bx
 	template<int32_t MantissaBits, int32_t ExpBits>
 	inline void encodeRgbE(float* _dst, const float* _src)
 	{
-		// Reference:
-		// https://www.opengl.org/registry/specs/EXT/texture_shared_exponent.txt
+		// Reference(s):
+		// - https://web.archive.org/web/20181126040035/https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_shared_exponent.txt
+		//
 		const int32_t expMax  = (1<<ExpBits) - 1;
 		const int32_t expBias = (1<<(ExpBits - 1) ) - 1;
 		const float   sharedExpMax = float(expMax) / float(expMax + 1) * float(1 << (expMax - expBias) );

+ 13 - 50
bx.mod/bx/include/bx/inline/readerwriter.inl

@@ -101,15 +101,15 @@ namespace bx
 		switch (_whence)
 		{
 			case Whence::Begin:
-				m_pos = int64_clamp(_offset, 0, m_top);
+				m_pos = clamp<int64_t>(_offset, 0, m_top);
 				break;
 
 			case Whence::Current:
-				m_pos = int64_clamp(m_pos + _offset, 0, m_top);
+				m_pos = clamp<int64_t>(m_pos + _offset, 0, m_top);
 				break;
 
 			case Whence::End:
-				m_pos = int64_clamp(m_top - _offset, 0, m_top);
+				m_pos = clamp<int64_t>(m_top - _offset, 0, m_top);
 				break;
 		}
 
@@ -128,7 +128,7 @@ namespace bx
 		}
 
 		int64_t remainder = m_top-m_pos;
-		int32_t size = uint32_min(_size, uint32_t(int64_min(remainder, INT32_MAX) ) );
+		int32_t size = uint32_min(_size, uint32_t(min<int64_t>(remainder, INT32_MAX) ) );
 		m_pos += size;
 		if (size != _size)
 		{
@@ -153,15 +153,15 @@ namespace bx
 		switch (_whence)
 		{
 			case Whence::Begin:
-				m_pos = int64_clamp(_offset, 0, m_top);
+				m_pos = clamp<int64_t>(_offset, 0, m_top);
 				break;
 
 			case Whence::Current:
-				m_pos = int64_clamp(m_pos + _offset, 0, m_top);
+				m_pos = clamp<int64_t>(m_pos + _offset, 0, m_top);
 				break;
 
 			case Whence::End:
-				m_pos = int64_clamp(m_top - _offset, 0, m_top);
+				m_pos = clamp<int64_t>(m_top - _offset, 0, m_top);
 				break;
 		}
 
@@ -173,7 +173,7 @@ namespace bx
 		BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
 
 		int64_t remainder = m_top-m_pos;
-		int32_t size = uint32_min(_size, uint32_t(int64_min(remainder, INT32_MAX) ) );
+		int32_t size = uint32_min(_size, uint32_t(min<int64_t>(remainder, INT32_MAX) ) );
 		memCopy(_data, &m_data[m_pos], size);
 		m_pos += size;
 		if (size != _size)
@@ -216,15 +216,15 @@ namespace bx
 		switch (_whence)
 		{
 			case Whence::Begin:
-				m_pos = int64_clamp(_offset, 0, m_top);
+				m_pos = clamp<int64_t>(_offset, 0, m_top);
 				break;
 
 			case Whence::Current:
-				m_pos = int64_clamp(m_pos + _offset, 0, m_top);
+				m_pos = clamp<int64_t>(m_pos + _offset, 0, m_top);
 				break;
 
 			case Whence::End:
-				m_pos = int64_clamp(m_top - _offset, 0, m_top);
+				m_pos = clamp<int64_t>(m_top - _offset, 0, m_top);
 				break;
 		}
 
@@ -245,10 +245,10 @@ namespace bx
 		}
 
 		int64_t remainder = m_size-m_pos;
-		int32_t size = uint32_min(_size, uint32_t(int64_min(remainder, INT32_MAX) ) );
+		int32_t size = uint32_min(_size, uint32_t(min<int64_t>(remainder, INT32_MAX) ) );
 		memCopy(&m_data[m_pos], _data, size);
 		m_pos += size;
-		m_top = int64_max(m_top, m_pos);
+		m_top = max(m_top, m_pos);
 		if (size != _size)
 		{
 			BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "MemoryWriter: write truncated.");
@@ -356,43 +356,6 @@ namespace bx
 		return result;
 	}
 
-	inline int32_t writePrintfVargs(WriterI* _writer, const char* _format, va_list _argList)
-	{
-		va_list argListCopy;
-		va_copy(argListCopy, _argList);
-
-		char temp[2048];
-		char*   out = temp;
-		int32_t max = sizeof(temp);
-		int32_t len = vsnprintf(out, max, _format, argListCopy);
-
-		va_end(argListCopy);
-
-		if (len > max)
-		{
-			va_copy(argListCopy, _argList);
-
-			out = (char*)alloca(len);
-			len = vsnprintf(out, len, _format, argListCopy);
-
-			va_end(argListCopy);
-		}
-
-		int32_t size = write(_writer, out, len);
-
-		return size;
-	}
-
-	inline int32_t writePrintf(WriterI* _writer, const char* _format, ...)
-	{
-		va_list argList;
-		va_start(argList, _format);
-		int32_t size = writePrintfVargs(_writer, _format, argList);
-		va_end(argList);
-
-		return size;
-	}
-
 	inline int64_t skip(SeekerI* _seeker, int64_t _offset)
 	{
 		return _seeker->seek(_offset, Whence::Current);

+ 21 - 24
bx.mod/bx/include/bx/inline/rng.inl

@@ -60,48 +60,45 @@ namespace bx
 	}
 
 	template <typename Rng>
-	inline void randUnitCircle(float _result[3], Rng* _rng)
+	inline bx::Vec3 randUnitCircle(Rng* _rng)
 	{
 		const float angle = frnd(_rng) * kPi2;
 
-		_result[0] = cos(angle);
-		_result[1] = 0.0f;
-		_result[2] = sin(angle);
+		return
+		{
+			cos(angle),
+			0.0f,
+			sin(angle),
+		};
 	}
 
 	template <typename Rng>
-	inline void randUnitSphere(float _result[3], Rng* _rng)
+	inline bx::Vec3 randUnitSphere(Rng* _rng)
 	{
 		const float rand0  = frnd(_rng) * 2.0f - 1.0f;
 		const float rand1  = frnd(_rng) * kPi2;
 		const float sqrtf1 = sqrt(1.0f - rand0*rand0);
 
-		_result[0] = sqrtf1 * cos(rand1);
-		_result[1] = sqrtf1 * sin(rand1);
-		_result[2] = rand0;
+		return
+		{
+			sqrtf1 * cos(rand1),
+			sqrtf1 * sin(rand1),
+			rand0,
+		};
 	}
 
 	template <typename Ty>
-	inline void randUnitHemisphere(float _result[3], Ty* _rng, const float _normal[3])
+	inline bx::Vec3 randUnitHemisphere(Ty* _rng, const bx::Vec3& _normal)
 	{
-		float dir[3];
-		randUnitSphere(dir, _rng);
-
-		float DdotN = dir[0]*_normal[0]
-					+ dir[1]*_normal[1]
-					+ dir[2]*_normal[2]
-					;
+		const bx::Vec3 dir = randUnitSphere(_rng);
+		const float ddotn  = bx::dot(dir, _normal);
 
-		if (0.0f > DdotN)
+		if (0.0f > ddotn)
 		{
-			dir[0] = -dir[0];
-			dir[1] = -dir[1];
-			dir[2] = -dir[2];
+			return bx::neg(dir);
 		}
 
-		_result[0] = dir[0];
-		_result[1] = dir[1];
-		_result[2] = dir[2];
+		return dir;
 	}
 
 	inline void generateSphereHammersley(void* _data, uint32_t _stride, uint32_t _num, float _scale)
@@ -141,7 +138,7 @@ namespace bx
 		for (uint32_t ii = 0, num = _num-1; ii < num; ++ii)
 		{
 			uint32_t jj = ii + 1 + _rng->gen() % (num - ii);
-			bx::xchg(_array[ii], _array[jj]);
+			bx::swap(_array[ii], _array[jj]);
 		}
 	}
 

+ 40 - 12
bx.mod/bx/include/bx/inline/string.inl

@@ -58,9 +58,9 @@ namespace bx
 		clear();
 	}
 
-	inline StringView::StringView(const StringView& _rhs)
+	inline StringView::StringView(const StringView& _rhs, int32_t _start, int32_t _len)
 	{
-		set(_rhs.m_ptr, _rhs.m_len);
+		set(_rhs, _start, _len);
 	}
 
 	inline StringView& StringView::operator=(const char* _rhs)
@@ -71,10 +71,25 @@ namespace bx
 
 	inline StringView& StringView::operator=(const StringView& _rhs)
 	{
-		set(_rhs.m_ptr, _rhs.m_len);
+		set(_rhs);
 		return *this;
 	}
 
+	inline StringView::StringView(char* _ptr)
+	{
+		set(_ptr, INT32_MAX);
+	}
+
+	inline StringView::StringView(const char* _ptr)
+	{
+		set(_ptr, INT32_MAX);
+	}
+
+	inline StringView::StringView(char* _ptr, int32_t _len)
+	{
+		set(_ptr, _len);
+	}
+
 	inline StringView::StringView(const char* _ptr, int32_t _len)
 	{
 		set(_ptr, _len);
@@ -91,18 +106,24 @@ namespace bx
 		set(_container);
 	}
 
+	inline void StringView::set(char* _ptr)
+	{
+		set(_ptr, INT32_MAX);
+	}
+
+	inline void StringView::set(const char* _ptr)
+	{
+		set(_ptr, INT32_MAX);
+	}
+
 	inline void StringView::set(const char* _ptr, int32_t _len)
 	{
 		clear();
 
 		if (NULL != _ptr)
 		{
-			int32_t len = strLen(_ptr, _len);
-			if (0 != len)
-			{
-				m_len = len;
-				m_ptr = _ptr;
-			}
+			m_len = INT32_MAX == _len ? strLen(_ptr) : _len;
+			m_ptr = _ptr;
 		}
 	}
 
@@ -114,12 +135,14 @@ namespace bx
 	template<typename Ty>
 	inline void StringView::set(const Ty& _container)
 	{
-		set(_container.data(), _container.length() );
+		set(_container.data(), int32_t(_container.length() ) );
 	}
 
-	inline void StringView::set(const StringView& _str)
+	inline void StringView::set(const StringView& _str, int32_t _start, int32_t _len)
 	{
-		set(_str.m_ptr, _str.m_len);
+		const int32_t start = min(_start, _str.m_len);
+		const int32_t len   = clamp(_str.m_len - start, 0, min(_len, _str.m_len) );
+		set(_str.m_ptr + start, len);
 	}
 
 	inline void StringView::clear()
@@ -213,4 +236,9 @@ namespace bx
 		}
 	}
 
+	inline StringView strSubstr(const StringView& _str, int32_t _start, int32_t _len)
+	{
+		return StringView(_str, _start, _len);
+	}
+
 } // namespace bx

+ 199 - 308
bx.mod/bx/include/bx/inline/uint32_t.inl

@@ -29,162 +29,162 @@
 
 namespace bx
 {
-	inline uint32_t uint32_li(uint32_t _a)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_li(uint32_t _a)
 	{
 		return _a;
 	}
 
-	inline uint32_t uint32_dec(uint32_t _a)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_dec(uint32_t _a)
 	{
 		return _a - 1;
 	}
 
-	inline uint32_t uint32_inc(uint32_t _a)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_inc(uint32_t _a)
 	{
 		return _a + 1;
 	}
 
-	inline uint32_t uint32_not(uint32_t _a)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_not(uint32_t _a)
 	{
 		return ~_a;
 	}
 
-	inline uint32_t uint32_neg(uint32_t _a)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_neg(uint32_t _a)
 	{
 		return -(int32_t)_a;
 	}
 
-	inline uint32_t uint32_ext(uint32_t _a)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_ext(uint32_t _a)
 	{
 		return ( (int32_t)_a)>>31;
 	}
 
-	inline uint32_t uint32_and(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_and(uint32_t _a, uint32_t _b)
 	{
 		return _a & _b;
 	}
 
-	inline uint32_t uint32_andc(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_andc(uint32_t _a, uint32_t _b)
 	{
 		return _a & ~_b;
 	}
 
-	inline uint32_t uint32_xor(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_xor(uint32_t _a, uint32_t _b)
 	{
 		return _a ^ _b;
 	}
 
-	inline uint32_t uint32_xorl(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_xorl(uint32_t _a, uint32_t _b)
 	{
 		return !_a != !_b;
 	}
 
-	inline uint32_t uint32_or(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_or(uint32_t _a, uint32_t _b)
 	{
 		return _a | _b;
 	}
 
-	inline uint32_t uint32_orc(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_orc(uint32_t _a, uint32_t _b)
 	{
 		return _a | ~_b;
 	}
 
-	inline uint32_t uint32_sll(uint32_t _a, int _sa)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_sll(uint32_t _a, int32_t _sa)
 	{
 		return _a << _sa;
 	}
 
-	inline uint32_t uint32_srl(uint32_t _a, int _sa)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_srl(uint32_t _a, int32_t _sa)
 	{
 		return _a >> _sa;
 	}
 
-	inline uint32_t uint32_sra(uint32_t _a, int _sa)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_sra(uint32_t _a, int32_t _sa)
 	{
 		return ( (int32_t)_a) >> _sa;
 	}
 
-	inline uint32_t uint32_rol(uint32_t _a, int _sa)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_rol(uint32_t _a, int32_t _sa)
 	{
 		return ( _a << _sa) | (_a >> (32-_sa) );
 	}
 
-	inline uint32_t uint32_ror(uint32_t _a, int _sa)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_ror(uint32_t _a, int32_t _sa)
 	{
 		return ( _a >> _sa) | (_a << (32-_sa) );
 	}
 
-	inline uint32_t uint32_add(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_add(uint32_t _a, uint32_t _b)
 	{
 		return _a + _b;
 	}
 
-	inline uint32_t uint32_iadd(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_iadd(uint32_t _a, uint32_t _b)
 	{
 		return int32_t(_a) + int32_t(_b);
 	}
 
-	inline uint32_t uint32_sub(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_sub(uint32_t _a, uint32_t _b)
 	{
 		return _a - _b;
 	}
 
-	inline uint32_t uint32_isub(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_isub(uint32_t _a, uint32_t _b)
 	{
 		return int32_t(_a) - int32_t(_b);
 	}
 
-	inline uint32_t uint32_mul(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_mul(uint32_t _a, uint32_t _b)
 	{
 		return _a * _b;
 	}
 
-	inline uint32_t uint32_div(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_div(uint32_t _a, uint32_t _b)
 	{
-		return (_a / _b);
+		return _a / _b;
 	}
 
-	inline uint32_t uint32_mod(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_mod(uint32_t _a, uint32_t _b)
 	{
-		return (_a % _b);
+		return _a % _b;
 	}
 
-	inline uint32_t uint32_cmpeq(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_cmpeq(uint32_t _a, uint32_t _b)
 	{
 		return -(_a == _b);
 	}
 
-	inline uint32_t uint32_cmpneq(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_cmpneq(uint32_t _a, uint32_t _b)
 	{
 		return -(_a != _b);
 	}
 
-	inline uint32_t uint32_cmplt(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_cmplt(uint32_t _a, uint32_t _b)
 	{
 		return -(_a < _b);
 	}
 
-	inline uint32_t uint32_cmple(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_cmple(uint32_t _a, uint32_t _b)
 	{
 		return -(_a <= _b);
 	}
 
-	inline uint32_t uint32_cmpgt(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_cmpgt(uint32_t _a, uint32_t _b)
 	{
 		return -(_a > _b);
 	}
 
-	inline uint32_t uint32_cmpge(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_cmpge(uint32_t _a, uint32_t _b)
 	{
 		return -(_a >= _b);
 	}
 
-	inline uint32_t uint32_setnz(uint32_t _a)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_setnz(uint32_t _a)
 	{
 		return -!!_a;
 	}
 
-	inline uint32_t uint32_satadd(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_satadd(uint32_t _a, uint32_t _b)
 	{
 		const uint32_t add    = uint32_add(_a, _b);
 		const uint32_t lt     = uint32_cmplt(add, _a);
@@ -193,7 +193,7 @@ namespace bx
 		return result;
 	}
 
-	inline uint32_t uint32_satsub(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_satsub(uint32_t _a, uint32_t _b)
 	{
 		const uint32_t sub    = uint32_sub(_a, _b);
 		const uint32_t le     = uint32_cmple(sub, _a);
@@ -202,7 +202,7 @@ namespace bx
 		return result;
 	}
 
-	inline uint32_t uint32_satmul(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_satmul(uint32_t _a, uint32_t _b)
 	{
 		const uint64_t mul    = (uint64_t)_a * (uint64_t)_b;
 		const uint32_t hi     = mul >> 32;
@@ -212,7 +212,7 @@ namespace bx
 		return result;
 	}
 
-	inline uint32_t uint32_sels(uint32_t test, uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_sels(uint32_t test, uint32_t _a, uint32_t _b)
 	{
 		const uint32_t mask   = uint32_ext(test);
 		const uint32_t sel_a  = uint32_and(_a, mask);
@@ -222,7 +222,7 @@ namespace bx
 		return (result);
 	}
 
-	inline uint32_t uint32_selb(uint32_t _mask, uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_selb(uint32_t _mask, uint32_t _a, uint32_t _b)
 	{
 		const uint32_t sel_a  = uint32_and(_a, _mask);
 		const uint32_t sel_b  = uint32_andc(_b, _mask);
@@ -231,7 +231,7 @@ namespace bx
 		return (result);
 	}
 
-	inline uint32_t uint32_imin(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_imin(uint32_t _a, uint32_t _b)
 	{
 		const uint32_t a_sub_b = uint32_sub(_a, _b);
 		const uint32_t result  = uint32_sels(a_sub_b, _a, _b);
@@ -239,7 +239,7 @@ namespace bx
 		return result;
 	}
 
-	inline uint32_t uint32_imax(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_imax(uint32_t _a, uint32_t _b)
 	{
 		const uint32_t b_sub_a = uint32_sub(_b, _a);
 		const uint32_t result  = uint32_sels(b_sub_a, _a, _b);
@@ -247,27 +247,27 @@ namespace bx
 		return result;
 	}
 
-	inline uint32_t uint32_min(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_min(uint32_t _a, uint32_t _b)
 	{
 		return _a > _b ? _b : _a;
 	}
 
-	inline uint32_t uint32_min(uint32_t _a, uint32_t _b, uint32_t _c)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_min(uint32_t _a, uint32_t _b, uint32_t _c)
 	{
 		return uint32_min(_a, uint32_min(_b, _c) );
 	}
 
-	inline uint32_t uint32_max(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_max(uint32_t _a, uint32_t _b)
 	{
 		return _a > _b ? _a : _b;
 	}
 
-	inline uint32_t uint32_max(uint32_t _a, uint32_t _b, uint32_t _c)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_max(uint32_t _a, uint32_t _b, uint32_t _c)
 	{
 		return uint32_max(_a, uint32_max(_b, _c) );
 	}
 
-	inline uint32_t uint32_clamp(uint32_t _a, uint32_t _min, uint32_t _max)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_clamp(uint32_t _a, uint32_t _min, uint32_t _max)
 	{
 		const uint32_t tmp    = uint32_max(_a, _min);
 		const uint32_t result = uint32_min(tmp, _max);
@@ -275,7 +275,7 @@ namespace bx
 		return result;
 	}
 
-	inline uint32_t uint32_iclamp(uint32_t _a, uint32_t _min, uint32_t _max)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_iclamp(uint32_t _a, uint32_t _min, uint32_t _max)
 	{
 		const uint32_t tmp    = uint32_imax(_a, _min);
 		const uint32_t result = uint32_imin(tmp, _max);
@@ -283,7 +283,7 @@ namespace bx
 		return result;
 	}
 
-	inline uint32_t uint32_incwrap(uint32_t _val, uint32_t _min, uint32_t _max)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_incwrap(uint32_t _val, uint32_t _min, uint32_t _max)
 	{
 		const uint32_t inc          = uint32_inc(_val);
 		const uint32_t max_diff     = uint32_sub(_max, _val);
@@ -295,7 +295,7 @@ namespace bx
 		return result;
 	}
 
-	inline uint32_t uint32_decwrap(uint32_t _val, uint32_t _min, uint32_t _max)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_decwrap(uint32_t _val, uint32_t _min, uint32_t _max)
 	{
 		const uint32_t dec          = uint32_dec(_val);
 		const uint32_t min_diff     = uint32_sub(_min, _val);
@@ -307,7 +307,7 @@ namespace bx
 		return result;
 	}
 
-	inline uint32_t uint32_cntbits_ref(uint32_t _val)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(uint32_t _val)
 	{
 		const uint32_t tmp0   = uint32_srl(_val, 1);
 		const uint32_t tmp1   = uint32_and(tmp0, 0x55555555);
@@ -330,19 +330,7 @@ namespace bx
 		return result;
 	}
 
-	/// Count number of bits set.
-	inline uint32_t uint32_cntbits(uint32_t _val)
-	{
-#if BX_COMPILER_GCC || BX_COMPILER_CLANG
-		return __builtin_popcount(_val);
-#elif BX_COMPILER_MSVC && BX_PLATFORM_WINDOWS
-		return __popcnt(_val);
-#else
-		return uint32_cntbits_ref(_val);
-#endif // BX_COMPILER_
-	}
-
-	inline uint32_t uint32_cntlz_ref(uint32_t _val)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(uint32_t _val)
 	{
 		const uint32_t tmp0   = uint32_srl(_val, 1);
 		const uint32_t tmp1   = uint32_or(tmp0, _val);
@@ -360,21 +348,7 @@ namespace bx
 		return result;
 	}
 
-	/// Count number of leading zeros.
-	inline uint32_t uint32_cntlz(uint32_t _val)
-	{
-#if BX_COMPILER_GCC || BX_COMPILER_CLANG
-		return __builtin_clz(_val);
-#elif BX_COMPILER_MSVC && BX_PLATFORM_WINDOWS
-		unsigned long index;
-		_BitScanReverse(&index, _val);
-		return 31 - index;
-#else
-		return uint32_cntlz_ref(_val);
-#endif // BX_COMPILER_
-	}
-
-	inline uint32_t uint32_cnttz_ref(uint32_t _val)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(uint32_t _val)
 	{
 		const uint32_t tmp0   = uint32_not(_val);
 		const uint32_t tmp1   = uint32_dec(_val);
@@ -384,25 +358,13 @@ namespace bx
 		return result;
 	}
 
-	inline uint32_t uint32_cnttz(uint32_t _val)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_part1by1(uint32_t _a)
 	{
-#if BX_COMPILER_GCC || BX_COMPILER_CLANG
-		return __builtin_ctz(_val);
-#elif BX_COMPILER_MSVC && BX_PLATFORM_WINDOWS
-		unsigned long index;
-		_BitScanForward(&index, _val);
-		return index;
-#else
-		return uint32_cnttz_ref(_val);
-#endif // BX_COMPILER_
-	}
+		// shuffle:
+		// ---- ---- ---- ---- fedc ba98 7654 3210
+		// to:
+		// -f-e -d-c -b-a -9-8 -7-6 -5-4 -3-2 -1-0
 
-	// shuffle:
-	// ---- ---- ---- ---- fedc ba98 7654 3210
-	// to:
-	// -f-e -d-c -b-a -9-8 -7-6 -5-4 -3-2 -1-0
-	inline uint32_t uint32_part1by1(uint32_t _a)
-	{
 		const uint32_t val    = uint32_and(_a, 0xffff);
 
 		const uint32_t tmp0   = uint32_sll(val, 8);
@@ -424,12 +386,13 @@ namespace bx
 		return result;
 	}
 
-	// shuffle:
-	// ---- ---- ---- ---- ---- --98 7654 3210
-	// to:
-	// ---- 9--8 --7- -6-- 5--4 --3- -2-- 1--0
-	inline uint32_t uint32_part1by2(uint32_t _a)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_part1by2(uint32_t _a)
 	{
+		// shuffle:
+		// ---- ---- ---- ---- ---- --98 7654 3210
+		// to:
+		// ---- 9--8 --7- -6-- 5--4 --3- -2-- 1--0
+
 		const uint32_t val    = uint32_and(_a, 0x3ff);
 
 		const uint32_t tmp0   = uint32_sll(val, 16);
@@ -451,7 +414,7 @@ namespace bx
 		return result;
 	}
 
-	inline uint32_t uint32_testpow2(uint32_t _a)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_testpow2(uint32_t _a)
 	{
 		const uint32_t tmp0   = uint32_dec(_a);
 		const uint32_t tmp1   = uint32_xor(_a, tmp0);
@@ -461,7 +424,7 @@ namespace bx
 		return result;
 	}
 
-	inline uint32_t uint32_nextpow2(uint32_t _a)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_nextpow2(uint32_t _a)
 	{
 		const uint32_t tmp0   = uint32_dec(_a);
 		const uint32_t tmp1   = uint32_srl(tmp0, 1);
@@ -479,151 +442,7 @@ namespace bx
 		return result;
 	}
 
-	inline uint16_t halfFromFloat(float _a)
-	{
-		union { uint32_t ui; float flt;	} ftou;
-		ftou.flt = _a;
-
-		const uint32_t one                        = uint32_li(0x00000001);
-		const uint32_t f_s_mask                   = uint32_li(0x80000000);
-		const uint32_t f_e_mask                   = uint32_li(0x7f800000);
-		const uint32_t f_m_mask                   = uint32_li(0x007fffff);
-		const uint32_t f_m_hidden_bit             = uint32_li(0x00800000);
-		const uint32_t f_m_round_bit              = uint32_li(0x00001000);
-		const uint32_t f_snan_mask                = uint32_li(0x7fc00000);
-		const uint32_t f_e_pos                    = uint32_li(0x00000017);
-		const uint32_t h_e_pos                    = uint32_li(0x0000000a);
-		const uint32_t h_e_mask                   = uint32_li(0x00007c00);
-		const uint32_t h_snan_mask                = uint32_li(0x00007e00);
-		const uint32_t h_e_mask_value             = uint32_li(0x0000001f);
-		const uint32_t f_h_s_pos_offset           = uint32_li(0x00000010);
-		const uint32_t f_h_bias_offset            = uint32_li(0x00000070);
-		const uint32_t f_h_m_pos_offset           = uint32_li(0x0000000d);
-		const uint32_t h_nan_min                  = uint32_li(0x00007c01);
-		const uint32_t f_h_e_biased_flag          = uint32_li(0x0000008f);
-		const uint32_t f_s                        = uint32_and(ftou.ui, f_s_mask);
-		const uint32_t f_e                        = uint32_and(ftou.ui, f_e_mask);
-		const uint16_t h_s              = (uint16_t)uint32_srl(f_s, f_h_s_pos_offset);
-		const uint32_t f_m                        = uint32_and(ftou.ui, f_m_mask);
-		const uint16_t f_e_amount       = (uint16_t)uint32_srl(f_e, f_e_pos);
-		const uint32_t f_e_half_bias              = uint32_sub(f_e_amount, f_h_bias_offset);
-		const uint32_t f_snan                     = uint32_and(ftou.ui, f_snan_mask);
-		const uint32_t f_m_round_mask             = uint32_and(f_m, f_m_round_bit);
-		const uint32_t f_m_round_offset           = uint32_sll(f_m_round_mask, one);
-		const uint32_t f_m_rounded                = uint32_add(f_m, f_m_round_offset);
-		const uint32_t f_m_denorm_sa              = uint32_sub(one, f_e_half_bias);
-		const uint32_t f_m_with_hidden            = uint32_or(f_m_rounded, f_m_hidden_bit);
-		const uint32_t f_m_denorm                 = uint32_srl(f_m_with_hidden, f_m_denorm_sa);
-		const uint32_t h_m_denorm                 = uint32_srl(f_m_denorm, f_h_m_pos_offset);
-		const uint32_t f_m_rounded_overflow       = uint32_and(f_m_rounded, f_m_hidden_bit);
-		const uint32_t m_nan                      = uint32_srl(f_m, f_h_m_pos_offset);
-		const uint32_t h_em_nan                   = uint32_or(h_e_mask, m_nan);
-		const uint32_t h_e_norm_overflow_offset   = uint32_inc(f_e_half_bias);
-		const uint32_t h_e_norm_overflow          = uint32_sll(h_e_norm_overflow_offset, h_e_pos);
-		const uint32_t h_e_norm                   = uint32_sll(f_e_half_bias, h_e_pos);
-		const uint32_t h_m_norm                   = uint32_srl(f_m_rounded, f_h_m_pos_offset);
-		const uint32_t h_em_norm                  = uint32_or(h_e_norm, h_m_norm);
-		const uint32_t is_h_ndenorm_msb           = uint32_sub(f_h_bias_offset, f_e_amount);
-		const uint32_t is_f_e_flagged_msb         = uint32_sub(f_h_e_biased_flag, f_e_half_bias);
-		const uint32_t is_h_denorm_msb            = uint32_not(is_h_ndenorm_msb);
-		const uint32_t is_f_m_eqz_msb             = uint32_dec(f_m);
-		const uint32_t is_h_nan_eqz_msb           = uint32_dec(m_nan);
-		const uint32_t is_f_inf_msb               = uint32_and(is_f_e_flagged_msb, is_f_m_eqz_msb);
-		const uint32_t is_f_nan_underflow_msb     = uint32_and(is_f_e_flagged_msb, is_h_nan_eqz_msb);
-		const uint32_t is_e_overflow_msb          = uint32_sub(h_e_mask_value, f_e_half_bias);
-		const uint32_t is_h_inf_msb               = uint32_or(is_e_overflow_msb, is_f_inf_msb);
-		const uint32_t is_f_nsnan_msb             = uint32_sub(f_snan, f_snan_mask);
-		const uint32_t is_m_norm_overflow_msb     = uint32_neg(f_m_rounded_overflow);
-		const uint32_t is_f_snan_msb              = uint32_not(is_f_nsnan_msb);
-		const uint32_t h_em_overflow_result       = uint32_sels(is_m_norm_overflow_msb, h_e_norm_overflow, h_em_norm);
-		const uint32_t h_em_nan_result            = uint32_sels(is_f_e_flagged_msb, h_em_nan, h_em_overflow_result);
-		const uint32_t h_em_nan_underflow_result  = uint32_sels(is_f_nan_underflow_msb, h_nan_min, h_em_nan_result);
-		const uint32_t h_em_inf_result            = uint32_sels(is_h_inf_msb, h_e_mask, h_em_nan_underflow_result);
-		const uint32_t h_em_denorm_result         = uint32_sels(is_h_denorm_msb, h_m_denorm, h_em_inf_result);
-		const uint32_t h_em_snan_result           = uint32_sels(is_f_snan_msb, h_snan_mask, h_em_denorm_result);
-		const uint32_t h_result                   = uint32_or(h_s, h_em_snan_result);
-
-		return (uint16_t)(h_result);
-	}
-
-	inline float halfToFloat(uint16_t _a)
-	{
-		const uint32_t h_e_mask              = uint32_li(0x00007c00);
-		const uint32_t h_m_mask              = uint32_li(0x000003ff);
-		const uint32_t h_s_mask              = uint32_li(0x00008000);
-		const uint32_t h_f_s_pos_offset      = uint32_li(0x00000010);
-		const uint32_t h_f_e_pos_offset      = uint32_li(0x0000000d);
-		const uint32_t h_f_bias_offset       = uint32_li(0x0001c000);
-		const uint32_t f_e_mask              = uint32_li(0x7f800000);
-		const uint32_t f_m_mask              = uint32_li(0x007fffff);
-		const uint32_t h_f_e_denorm_bias     = uint32_li(0x0000007e);
-		const uint32_t h_f_m_denorm_sa_bias  = uint32_li(0x00000008);
-		const uint32_t f_e_pos               = uint32_li(0x00000017);
-		const uint32_t h_e_mask_minus_one    = uint32_li(0x00007bff);
-		const uint32_t h_e                   = uint32_and(_a, h_e_mask);
-		const uint32_t h_m                   = uint32_and(_a, h_m_mask);
-		const uint32_t h_s                   = uint32_and(_a, h_s_mask);
-		const uint32_t h_e_f_bias            = uint32_add(h_e, h_f_bias_offset);
-		const uint32_t h_m_nlz               = uint32_cntlz(h_m);
-		const uint32_t f_s                   = uint32_sll(h_s, h_f_s_pos_offset);
-		const uint32_t f_e                   = uint32_sll(h_e_f_bias, h_f_e_pos_offset);
-		const uint32_t f_m                   = uint32_sll(h_m, h_f_e_pos_offset);
-		const uint32_t f_em                  = uint32_or(f_e, f_m);
-		const uint32_t h_f_m_sa              = uint32_sub(h_m_nlz, h_f_m_denorm_sa_bias);
-		const uint32_t f_e_denorm_unpacked   = uint32_sub(h_f_e_denorm_bias, h_f_m_sa);
-		const uint32_t h_f_m                 = uint32_sll(h_m, h_f_m_sa);
-		const uint32_t f_m_denorm            = uint32_and(h_f_m, f_m_mask);
-		const uint32_t f_e_denorm            = uint32_sll(f_e_denorm_unpacked, f_e_pos);
-		const uint32_t f_em_denorm           = uint32_or(f_e_denorm, f_m_denorm);
-		const uint32_t f_em_nan              = uint32_or(f_e_mask, f_m);
-		const uint32_t is_e_eqz_msb          = uint32_dec(h_e);
-		const uint32_t is_m_nez_msb          = uint32_neg(h_m);
-		const uint32_t is_e_flagged_msb      = uint32_sub(h_e_mask_minus_one, h_e);
-		const uint32_t is_zero_msb           = uint32_andc(is_e_eqz_msb, is_m_nez_msb);
-		const uint32_t is_inf_msb            = uint32_andc(is_e_flagged_msb, is_m_nez_msb);
-		const uint32_t is_denorm_msb         = uint32_and(is_m_nez_msb, is_e_eqz_msb);
-		const uint32_t is_nan_msb            = uint32_and(is_e_flagged_msb, is_m_nez_msb);
-		const uint32_t is_zero               = uint32_ext(is_zero_msb);
-		const uint32_t f_zero_result         = uint32_andc(f_em, is_zero);
-		const uint32_t f_denorm_result       = uint32_sels(is_denorm_msb, f_em_denorm, f_zero_result);
-		const uint32_t f_inf_result          = uint32_sels(is_inf_msb, f_e_mask, f_denorm_result);
-		const uint32_t f_nan_result          = uint32_sels(is_nan_msb, f_em_nan, f_inf_result);
-		const uint32_t f_result              = uint32_or(f_s, f_nan_result);
-
-		union { uint32_t ui; float flt;	} utof;
-		utof.ui = f_result;
-		return utof.flt;
-	}
-
-	inline uint16_t uint16_min(uint16_t _a, uint16_t _b)
-	{
-		return _a > _b ? _b : _a;
-	}
-
-	inline uint16_t uint16_max(uint16_t _a, uint16_t _b)
-	{
-		return _a < _b ? _b : _a;
-	}
-
-	inline int64_t int64_min(int64_t _a, int64_t _b)
-	{
-		return _a < _b ? _a : _b;
-	}
-
-	inline int64_t int64_max(int64_t _a, int64_t _b)
-	{
-		return _a > _b ? _a : _b;
-	}
-
-	inline int64_t int64_clamp(int64_t _a, int64_t _min, int64_t _max)
-	{
-		const int64_t min    = int64_min(_a, _max);
-		const int64_t result = int64_max(_min, min);
-
-		return result;
-	}
-
-	inline uint32_t uint64_cntbits_ref(uint64_t _val)
+	inline BX_CONSTEXPR_FUNC uint32_t uint64_cntbits(uint64_t _val)
 	{
 		const uint32_t lo = uint32_t(_val&UINT32_MAX);
 		const uint32_t hi = uint32_t(_val>>32);
@@ -633,19 +452,7 @@ namespace bx
 		return total;
 	}
 
-	/// Count number of bits set.
-	inline uint32_t uint64_cntbits(uint64_t _val)
-	{
-#if BX_COMPILER_GCC || BX_COMPILER_CLANG
-		return __builtin_popcountll(_val);
-#elif BX_COMPILER_MSVC && BX_ARCH_64BIT
-		return uint32_t(__popcnt64(_val) );
-#else
-		return uint64_cntbits_ref(_val);
-#endif // BX_COMPILER_
-	}
-
-	inline uint32_t uint64_cntlz_ref(uint64_t _val)
+	inline BX_CONSTEXPR_FUNC uint32_t uint64_cntlz(uint64_t _val)
 	{
 		return _val & UINT64_C(0xffffffff00000000)
 			 ? uint32_cntlz(uint32_t(_val>>32) )
@@ -653,21 +460,7 @@ namespace bx
 			 ;
 	}
 
-	/// Count number of leading zeros.
-	inline uint32_t uint64_cntlz(uint64_t _val)
-	{
-#if BX_COMPILER_GCC || BX_COMPILER_CLANG
-		return __builtin_clzll(_val);
-#elif BX_COMPILER_MSVC && BX_PLATFORM_WINDOWS && BX_ARCH_64BIT
-		unsigned long index;
-		_BitScanReverse64(&index, _val);
-		return uint32_t(63 - index);
-#else
-		return uint64_cntlz_ref(_val);
-#endif // BX_COMPILER_
-	}
-
-	inline uint32_t uint64_cnttz_ref(uint64_t _val)
+	inline BX_CONSTEXPR_FUNC uint32_t uint64_cnttz(uint64_t _val)
 	{
 		return _val & UINT64_C(0xffffffff)
 			? uint32_cnttz(uint32_t(_val) )
@@ -675,65 +468,51 @@ namespace bx
 			;
 	}
 
-	inline uint32_t uint64_cnttz(uint64_t _val)
-	{
-#if BX_COMPILER_GCC || BX_COMPILER_CLANG
-		return __builtin_ctzll(_val);
-#elif BX_COMPILER_MSVC && BX_PLATFORM_WINDOWS && BX_ARCH_64BIT
-		unsigned long index;
-		_BitScanForward64(&index, _val);
-		return uint32_t(index);
-#else
-		return uint64_cnttz_ref(_val);
-#endif // BX_COMPILER_
-	}
-
-	inline uint64_t uint64_sll(uint64_t _a, int _sa)
+	inline BX_CONSTEXPR_FUNC uint64_t uint64_sll(uint64_t _a, int32_t _sa)
 	{
 		return _a << _sa;
 	}
 
-	inline uint64_t uint64_srl(uint64_t _a, int _sa)
+	inline BX_CONSTEXPR_FUNC uint64_t uint64_srl(uint64_t _a, int32_t _sa)
 	{
 		return _a >> _sa;
 	}
 
-	inline uint64_t uint64_sra(uint64_t _a, int _sa)
+	inline BX_CONSTEXPR_FUNC uint64_t uint64_sra(uint64_t _a, int32_t _sa)
 	{
 		return ( (int64_t)_a) >> _sa;
 	}
 
-	inline uint64_t uint64_rol(uint64_t _a, int _sa)
+	inline BX_CONSTEXPR_FUNC uint64_t uint64_rol(uint64_t _a, int32_t _sa)
 	{
-		return ( _a << _sa) | (_a >> (32-_sa) );
+		return ( _a << _sa) | (_a >> (64-_sa) );
 	}
 
-	inline uint64_t uint64_ror(uint64_t _a, int _sa)
+	inline BX_CONSTEXPR_FUNC uint64_t uint64_ror(uint64_t _a, int32_t _sa)
 	{
-		return ( _a >> _sa) | (_a << (32-_sa) );
+		return ( _a >> _sa) | (_a << (64-_sa) );
 	}
 
-	inline uint64_t uint64_add(uint64_t _a, uint64_t _b)
+	inline BX_CONSTEXPR_FUNC uint64_t uint64_add(uint64_t _a, uint64_t _b)
 	{
 		return _a + _b;
 	}
 
-	inline uint64_t uint64_sub(uint64_t _a, uint64_t _b)
+	inline BX_CONSTEXPR_FUNC uint64_t uint64_sub(uint64_t _a, uint64_t _b)
 	{
 		return _a - _b;
 	}
 
-	inline uint64_t uint64_mul(uint64_t _a, uint64_t _b)
+	inline BX_CONSTEXPR_FUNC uint64_t uint64_mul(uint64_t _a, uint64_t _b)
 	{
 		return _a * _b;
 	}
 
-	/// Greatest common divisor.
-	inline uint32_t uint32_gcd(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_gcd(uint32_t _a, uint32_t _b)
 	{
 		do
 		{
-			uint32_t tmp = _a % _b;
+			const uint32_t tmp = uint32_mod(_a, _b);
 			_a = _b;
 			_b = tmp;
 		}
@@ -742,14 +521,12 @@ namespace bx
 		return _a;
 	}
 
-	/// Least common multiple.
-	inline uint32_t uint32_lcm(uint32_t _a, uint32_t _b)
+	inline BX_CONSTEXPR_FUNC uint32_t uint32_lcm(uint32_t _a, uint32_t _b)
 	{
 		return _a * (_b / uint32_gcd(_a, _b) );
 	}
 
-	/// Align to arbitrary stride.
-	inline uint32_t strideAlign(uint32_t _offset, uint32_t _stride)
+	inline BX_CONSTEXPR_FUNC uint32_t strideAlign(uint32_t _offset, uint32_t _stride)
 	{
 		const uint32_t mod    = uint32_mod(_offset, _stride);
 		const uint32_t add    = uint32_sub(_stride, mod);
@@ -760,8 +537,7 @@ namespace bx
 		return result;
 	}
 
-	/// Align to arbitrary stride and 16-bytes.
-	inline uint32_t strideAlign16(uint32_t _offset, uint32_t _stride)
+	inline BX_CONSTEXPR_FUNC uint32_t strideAlign16(uint32_t _offset, uint32_t _stride)
 	{
 		const uint32_t align  = uint32_lcm(16, _stride);
 		const uint32_t mod    = uint32_mod(_offset, align);
@@ -773,8 +549,7 @@ namespace bx
 		return result;
 	}
 
-	/// Align to arbitrary stride and 256-bytes.
-	inline uint32_t strideAlign256(uint32_t _offset, uint32_t _stride)
+	inline BX_CONSTEXPR_FUNC uint32_t strideAlign256(uint32_t _offset, uint32_t _stride)
 	{
 		const uint32_t align  = uint32_lcm(256, _stride);
 		const uint32_t mod    = uint32_mod(_offset, align);
@@ -786,4 +561,120 @@ namespace bx
 		return result;
 	}
 
+	inline BX_CONST_FUNC uint16_t halfFromFloat(float _a)
+	{
+		union { uint32_t ui; float flt; } ftou;
+		ftou.flt = _a;
+
+		const uint32_t one                       = uint32_li(0x00000001);
+		const uint32_t f_s_mask                  = uint32_li(0x80000000);
+		const uint32_t f_e_mask                  = uint32_li(0x7f800000);
+		const uint32_t f_m_mask                  = uint32_li(0x007fffff);
+		const uint32_t f_m_hidden_bit            = uint32_li(0x00800000);
+		const uint32_t f_m_round_bit             = uint32_li(0x00001000);
+		const uint32_t f_snan_mask               = uint32_li(0x7fc00000);
+		const uint32_t f_e_pos                   = uint32_li(0x00000017);
+		const uint32_t h_e_pos                   = uint32_li(0x0000000a);
+		const uint32_t h_e_mask                  = uint32_li(0x00007c00);
+		const uint32_t h_snan_mask               = uint32_li(0x00007e00);
+		const uint32_t h_e_mask_value            = uint32_li(0x0000001f);
+		const uint32_t f_h_s_pos_offset          = uint32_li(0x00000010);
+		const uint32_t f_h_bias_offset           = uint32_li(0x00000070);
+		const uint32_t f_h_m_pos_offset          = uint32_li(0x0000000d);
+		const uint32_t h_nan_min                 = uint32_li(0x00007c01);
+		const uint32_t f_h_e_biased_flag         = uint32_li(0x0000008f);
+		const uint32_t f_s                       = uint32_and(ftou.ui, f_s_mask);
+		const uint32_t f_e                       = uint32_and(ftou.ui, f_e_mask);
+		const uint16_t h_s                       = (uint16_t)uint32_srl(f_s, f_h_s_pos_offset);
+		const uint32_t f_m                       = uint32_and(ftou.ui, f_m_mask);
+		const uint16_t f_e_amount                = (uint16_t)uint32_srl(f_e, f_e_pos);
+		const uint32_t f_e_half_bias             = uint32_sub(f_e_amount, f_h_bias_offset);
+		const uint32_t f_snan                    = uint32_and(ftou.ui, f_snan_mask);
+		const uint32_t f_m_round_mask            = uint32_and(f_m, f_m_round_bit);
+		const uint32_t f_m_round_offset          = uint32_sll(f_m_round_mask, one);
+		const uint32_t f_m_rounded               = uint32_add(f_m, f_m_round_offset);
+		const uint32_t f_m_denorm_sa             = uint32_sub(one, f_e_half_bias);
+		const uint32_t f_m_with_hidden           = uint32_or(f_m_rounded, f_m_hidden_bit);
+		const uint32_t f_m_denorm                = uint32_srl(f_m_with_hidden, f_m_denorm_sa);
+		const uint32_t h_m_denorm                = uint32_srl(f_m_denorm, f_h_m_pos_offset);
+		const uint32_t f_m_rounded_overflow      = uint32_and(f_m_rounded, f_m_hidden_bit);
+		const uint32_t m_nan                     = uint32_srl(f_m, f_h_m_pos_offset);
+		const uint32_t h_em_nan                  = uint32_or(h_e_mask, m_nan);
+		const uint32_t h_e_norm_overflow_offset  = uint32_inc(f_e_half_bias);
+		const uint32_t h_e_norm_overflow         = uint32_sll(h_e_norm_overflow_offset, h_e_pos);
+		const uint32_t h_e_norm                  = uint32_sll(f_e_half_bias, h_e_pos);
+		const uint32_t h_m_norm                  = uint32_srl(f_m_rounded, f_h_m_pos_offset);
+		const uint32_t h_em_norm                 = uint32_or(h_e_norm, h_m_norm);
+		const uint32_t is_h_ndenorm_msb          = uint32_sub(f_h_bias_offset, f_e_amount);
+		const uint32_t is_f_e_flagged_msb        = uint32_sub(f_h_e_biased_flag, f_e_half_bias);
+		const uint32_t is_h_denorm_msb           = uint32_not(is_h_ndenorm_msb);
+		const uint32_t is_f_m_eqz_msb            = uint32_dec(f_m);
+		const uint32_t is_h_nan_eqz_msb          = uint32_dec(m_nan);
+		const uint32_t is_f_inf_msb              = uint32_and(is_f_e_flagged_msb, is_f_m_eqz_msb);
+		const uint32_t is_f_nan_underflow_msb    = uint32_and(is_f_e_flagged_msb, is_h_nan_eqz_msb);
+		const uint32_t is_e_overflow_msb         = uint32_sub(h_e_mask_value, f_e_half_bias);
+		const uint32_t is_h_inf_msb              = uint32_or(is_e_overflow_msb, is_f_inf_msb);
+		const uint32_t is_f_nsnan_msb            = uint32_sub(f_snan, f_snan_mask);
+		const uint32_t is_m_norm_overflow_msb    = uint32_neg(f_m_rounded_overflow);
+		const uint32_t is_f_snan_msb             = uint32_not(is_f_nsnan_msb);
+		const uint32_t h_em_overflow_result      = uint32_sels(is_m_norm_overflow_msb, h_e_norm_overflow, h_em_norm);
+		const uint32_t h_em_nan_result           = uint32_sels(is_f_e_flagged_msb, h_em_nan, h_em_overflow_result);
+		const uint32_t h_em_nan_underflow_result = uint32_sels(is_f_nan_underflow_msb, h_nan_min, h_em_nan_result);
+		const uint32_t h_em_inf_result           = uint32_sels(is_h_inf_msb, h_e_mask, h_em_nan_underflow_result);
+		const uint32_t h_em_denorm_result        = uint32_sels(is_h_denorm_msb, h_m_denorm, h_em_inf_result);
+		const uint32_t h_em_snan_result          = uint32_sels(is_f_snan_msb, h_snan_mask, h_em_denorm_result);
+		const uint32_t h_result                  = uint32_or(h_s, h_em_snan_result);
+
+		return (uint16_t)(h_result);
+	}
+
+	inline BX_CONST_FUNC float halfToFloat(uint16_t _a)
+	{
+		const uint32_t h_e_mask             = uint32_li(0x00007c00);
+		const uint32_t h_m_mask             = uint32_li(0x000003ff);
+		const uint32_t h_s_mask             = uint32_li(0x00008000);
+		const uint32_t h_f_s_pos_offset     = uint32_li(0x00000010);
+		const uint32_t h_f_e_pos_offset     = uint32_li(0x0000000d);
+		const uint32_t h_f_bias_offset      = uint32_li(0x0001c000);
+		const uint32_t f_e_mask             = uint32_li(0x7f800000);
+		const uint32_t f_m_mask             = uint32_li(0x007fffff);
+		const uint32_t h_f_e_denorm_bias    = uint32_li(0x0000007e);
+		const uint32_t h_f_m_denorm_sa_bias = uint32_li(0x00000008);
+		const uint32_t f_e_pos              = uint32_li(0x00000017);
+		const uint32_t h_e_mask_minus_one   = uint32_li(0x00007bff);
+		const uint32_t h_e                  = uint32_and(_a, h_e_mask);
+		const uint32_t h_m                  = uint32_and(_a, h_m_mask);
+		const uint32_t h_s                  = uint32_and(_a, h_s_mask);
+		const uint32_t h_e_f_bias           = uint32_add(h_e, h_f_bias_offset);
+		const uint32_t h_m_nlz              = uint32_cntlz(h_m);
+		const uint32_t f_s                  = uint32_sll(h_s, h_f_s_pos_offset);
+		const uint32_t f_e                  = uint32_sll(h_e_f_bias, h_f_e_pos_offset);
+		const uint32_t f_m                  = uint32_sll(h_m, h_f_e_pos_offset);
+		const uint32_t f_em                 = uint32_or(f_e, f_m);
+		const uint32_t h_f_m_sa             = uint32_sub(h_m_nlz, h_f_m_denorm_sa_bias);
+		const uint32_t f_e_denorm_unpacked  = uint32_sub(h_f_e_denorm_bias, h_f_m_sa);
+		const uint32_t h_f_m                = uint32_sll(h_m, h_f_m_sa);
+		const uint32_t f_m_denorm           = uint32_and(h_f_m, f_m_mask);
+		const uint32_t f_e_denorm           = uint32_sll(f_e_denorm_unpacked, f_e_pos);
+		const uint32_t f_em_denorm          = uint32_or(f_e_denorm, f_m_denorm);
+		const uint32_t f_em_nan             = uint32_or(f_e_mask, f_m);
+		const uint32_t is_e_eqz_msb         = uint32_dec(h_e);
+		const uint32_t is_m_nez_msb         = uint32_neg(h_m);
+		const uint32_t is_e_flagged_msb     = uint32_sub(h_e_mask_minus_one, h_e);
+		const uint32_t is_zero_msb          = uint32_andc(is_e_eqz_msb, is_m_nez_msb);
+		const uint32_t is_inf_msb           = uint32_andc(is_e_flagged_msb, is_m_nez_msb);
+		const uint32_t is_denorm_msb        = uint32_and(is_m_nez_msb, is_e_eqz_msb);
+		const uint32_t is_nan_msb           = uint32_and(is_e_flagged_msb, is_m_nez_msb);
+		const uint32_t is_zero              = uint32_ext(is_zero_msb);
+		const uint32_t f_zero_result        = uint32_andc(f_em, is_zero);
+		const uint32_t f_denorm_result      = uint32_sels(is_denorm_msb, f_em_denorm, f_zero_result);
+		const uint32_t f_inf_result         = uint32_sels(is_inf_msb, f_e_mask, f_denorm_result);
+		const uint32_t f_nan_result         = uint32_sels(is_nan_msb, f_em_nan, f_inf_result);
+		const uint32_t f_result             = uint32_or(f_s, f_nan_result);
+
+		union { uint32_t ui; float flt; } utof;
+		utof.ui = f_result;
+		return utof.flt;
+	}
+
 } // namespace bx

+ 14 - 8
bx.mod/bx/include/bx/macros.h

@@ -46,6 +46,7 @@
 #define BX_ALIGN_256(_value) BX_ALIGN_MASK(_value, 0xff)
 #define BX_ALIGN_4096(_value) BX_ALIGN_MASK(_value, 0xfff)
 
+///
 #define BX_ALIGNOF(_type) __alignof(_type)
 
 #if defined(__has_feature)
@@ -112,6 +113,11 @@
 #	error "Unknown BX_COMPILER_?"
 #endif
 
+/// The return value of the function is solely a function of the arguments.
+///
+#define BX_CONSTEXPR_FUNC constexpr BX_CONST_FUNC
+
+///
 #define BX_STATIC_ASSERT(_condition, ...) static_assert(_condition, "" __VA_ARGS__)
 
 ///
@@ -199,19 +205,19 @@
 
 ///
 #define BX_CLASS_NO_DEFAULT_CTOR(_class) \
-			private: _class()
+	private: _class()
 
 #define BX_CLASS_NO_COPY(_class) \
-			private: _class(const _class& _rhs)
+	private: _class(const _class& _rhs)
 
 #define BX_CLASS_NO_ASSIGNMENT(_class) \
-			private: _class& operator=(const _class& _rhs)
+	private: _class& operator=(const _class& _rhs)
 
-#define BX_CLASS_ALLOCATOR(_class) \
-			public: void* operator new(size_t _size); \
-			public: void  operator delete(void* _ptr); \
-			public: void* operator new[](size_t _size); \
-			public: void  operator delete[](void* _ptr)
+#define BX_CLASS_ALLOCATOR(_class)              \
+	public: void* operator new(size_t _size);   \
+	public: void  operator delete(void* _ptr);  \
+	public: void* operator new[](size_t _size); \
+	public: void  operator delete[](void* _ptr)
 
 #define BX_CLASS_1(_class, _a1) BX_CONCATENATE(BX_CLASS_, _a1)(_class)
 #define BX_CLASS_2(_class, _a1, _a2) BX_CLASS_1(_class, _a1); BX_CLASS_1(_class, _a2)

+ 96 - 82
bx.mod/bx/include/bx/math.h

@@ -3,8 +3,6 @@
  * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
  */
 
-// FPU math lib
-
 #ifndef BX_MATH_H_HEADER_GUARD
 #define BX_MATH_H_HEADER_GUARD
 
@@ -13,21 +11,21 @@
 
 namespace bx
 {
-	extern const float kPi;
-	extern const float kPi2;
-	extern const float kInvPi;
-	extern const float kPiHalf;
-	extern const float kPiQuarter;
-	extern const float kSqrt2;
-	extern const float kLogNat10;
-	extern const float kInvLogNat2;
-	extern const float kLogNat2Hi;
-	extern const float kLogNat2Lo;
-	extern const float kE;
-	extern const float kNearZero;
+	constexpr float kPi         = 3.1415926535897932384626433832795f;
+	constexpr float kPi2        = 6.2831853071795864769252867665590f;
+	constexpr float kInvPi      = 1.0f/kPi;
+	constexpr float kPiHalf     = 1.5707963267948966192313216916398f;
+	constexpr float kPiQuarter  = 0.7853981633974483096156608458199f;
+	constexpr float kSqrt2      = 1.4142135623730950488016887242097f;
+	constexpr float kLogNat10   = 2.3025850929940456840179914546844f;
+	constexpr float kInvLogNat2 = 1.4426950408889634073599246810019f;
+	constexpr float kLogNat2Hi  = 0.6931471805599453094172321214582f;
+	constexpr float kLogNat2Lo  = 1.90821492927058770002e-10f;
+	constexpr float kE          = 2.7182818284590452353602874713527f;
+	constexpr float kNearZero   = 1.0f/float(1 << 28);
+	constexpr float kFloatMin   = 1.175494e-38f;
+	constexpr float kFloatMax   = 3.402823e+38f;
 	extern const float kInfinity;
-	extern const float kFloatMin;
-	extern const float kFloatMax;
 
 	///
 	typedef float (*LerpFn)(float _a, float _b, float _t);
@@ -52,6 +50,18 @@ namespace bx
 		};
 	};
 
+	///
+	struct Vec3
+	{
+		float x, y, z;
+	};
+
+	///
+	struct Quaternion
+	{
+		float x, y, z, w;
+	};
+
 	/// Returns converted the argument _deg to radians.
 	///
 	BX_CONST_FUNC float toRad(float _deg);
@@ -106,31 +116,31 @@ namespace bx
 
 	/// Returns the largest integer value not greater than _f.
 	///
-	BX_CONST_FUNC float floor(float _f);
+	BX_CONSTEXPR_FUNC float floor(float _f);
 
 	/// Returns the smallest integer value not less than _f.
 	///
-	BX_CONST_FUNC float ceil(float _f);
+	BX_CONSTEXPR_FUNC float ceil(float _f);
 
 	/// Returns the nearest integer value to _f, rounding halfway cases away from zero,
 	///
-	BX_CONST_FUNC float round(float _f);
+	BX_CONSTEXPR_FUNC float round(float _f);
 
 	/// Returns linear interpolation between two values _a and _b.
 	///
-	BX_CONST_FUNC float lerp(float _a, float _b, float _t);
+	BX_CONSTEXPR_FUNC float lerp(float _a, float _b, float _t);
 
 	/// Returns the sign of _a.
 	///
-	BX_CONST_FUNC float sign(float _a);
+	BX_CONSTEXPR_FUNC float sign(float _a);
 
 	/// Returns the absolute of _a.
 	///
-	BX_CONST_FUNC float abs(float _a);
+	BX_CONSTEXPR_FUNC float abs(float _a);
 
 	/// Returns the square of _a.
 	///
-	BX_CONST_FUNC float square(float _a);
+	BX_CONSTEXPR_FUNC float square(float _a);
 
 	/// Returns the cosine of the argument _a.
 	///
@@ -211,23 +221,23 @@ namespace bx
 
 	/// Returns the nearest integer not greater in magnitude than _a.
 	///
-	BX_CONST_FUNC float trunc(float _a);
+	BX_CONSTEXPR_FUNC float trunc(float _a);
 
 	/// Returns the fractional (or decimal) part of _a, which is greater than or equal to 0
 	/// and less than 1.
 	///
-	BX_CONST_FUNC float fract(float _a);
+	BX_CONSTEXPR_FUNC float fract(float _a);
 
 	/// Returns result of multipla and add (_a * _b + _c).
 	///
-	BX_CONST_FUNC float mad(float _a, float _b, float _c);
+	BX_CONSTEXPR_FUNC float mad(float _a, float _b, float _c);
 
 	/// Returns the floating-point remainder of the division operation _a/_b.
 	///
 	BX_CONST_FUNC float mod(float _a, float _b);
 
 	///
-	BX_CONST_FUNC bool equal(float _a, float _b, float _epsilon);
+	BX_CONSTEXPR_FUNC bool equal(float _a, float _b, float _epsilon);
 
 	///
 	BX_CONST_FUNC bool equal(const float* _a, const float* _b, uint32_t _num, float _epsilon);
@@ -236,23 +246,19 @@ namespace bx
 	BX_CONST_FUNC float wrap(float _a, float _wrap);
 
 	///
-	BX_CONST_FUNC float step(float _edge, float _a);
+	BX_CONSTEXPR_FUNC float step(float _edge, float _a);
 
 	///
-	BX_CONST_FUNC float pulse(float _a, float _start, float _end);
+	BX_CONSTEXPR_FUNC float pulse(float _a, float _start, float _end);
 
 	///
-	BX_CONST_FUNC float smoothStep(float _a);
+	BX_CONSTEXPR_FUNC float smoothStep(float _a);
 
-	// References:
-	//  - Bias And Gain Are Your Friend
-	//    http://blog.demofox.org/2012/09/24/bias-and-gain-are-your-friend/
-	//  - http://demofox.org/biasgain.html
 	///
-	BX_CONST_FUNC float bias(float _time, float _bias);
+	BX_CONSTEXPR_FUNC float bias(float _time, float _bias);
 
 	///
-	BX_CONST_FUNC float gain(float _time, float _gain);
+	BX_CONSTEXPR_FUNC float gain(float _time, float _gain);
 
 	///
 	BX_CONST_FUNC float angleDiff(float _a, float _b);
@@ -262,116 +268,121 @@ namespace bx
 	BX_CONST_FUNC float angleLerp(float _a, float _b, float _t);
 
 	///
-	void vec3Move(float* _result, const float* _a);
+	Vec3 load(const void* _ptr);
 
 	///
-	void vec3Abs(float* _result, const float* _a);
+	void store(void* _ptr, const Vec3 _a);
 
 	///
-	void vec3Neg(float* _result, const float* _a);
+	BX_CONSTEXPR_FUNC Vec3 abs(const Vec3 _a);
 
 	///
-	void vec3Add(float* _result, const float* _a, const float* _b);
+	BX_CONSTEXPR_FUNC Vec3 neg(const Vec3 _a);
 
 	///
-	void vec3Add(float* _result, const float* _a, float _b);
+	BX_CONSTEXPR_FUNC Vec3 add(const Vec3 _a, const Vec3 _b);
 
 	///
-	void vec3Sub(float* _result, const float* _a, const float* _b);
+	BX_CONSTEXPR_FUNC Vec3 add(const Vec3 _a, float _b);
 
 	///
-	void vec3Sub(float* _result, const float* _a, float _b);
+	BX_CONSTEXPR_FUNC Vec3 sub(const Vec3 _a, const Vec3 _b);
 
 	///
-	void vec3Mul(float* _result, const float* _a, const float* _b);
+	BX_CONSTEXPR_FUNC Vec3 sub(const Vec3 _a, float _b);
 
 	///
-	void vec3Mul(float* _result, const float* _a, float _b);
+	BX_CONSTEXPR_FUNC Vec3 mul(const Vec3 _a, const Vec3 _b);
 
 	///
-	float vec3Dot(const float* _a, const float* _b);
+	BX_CONSTEXPR_FUNC Vec3 mul(const Vec3 _a, float _b);
 
 	///
-	void vec3Cross(float* _result, const float* _a, const float* _b);
+	BX_CONSTEXPR_FUNC Vec3 mad(const Vec3 _a, const float _b, const Vec3 _c);
 
 	///
-	float vec3Length(const float* _a);
+	BX_CONSTEXPR_FUNC Vec3 mad(const Vec3 _a, const Vec3 _b, const Vec3 _c);
 
 	///
-	void vec3Lerp(float* _result, const float* _a, const float* _b, float _t);
+	BX_CONSTEXPR_FUNC float dot(const Vec3 _a, const Vec3 _b);
 
 	///
-	void vec3Lerp(float* _result, const float* _a, const float* _b, const float* _c);
+	BX_CONSTEXPR_FUNC Vec3 cross(const Vec3 _a, const Vec3 _b);
 
 	///
-	float vec3Norm(float* _result, const float* _a);
+	BX_CONST_FUNC float length(const Vec3 _a);
 
 	///
-	void vec3Min(float* _result, const float* _a, const float* _b);
+	BX_CONSTEXPR_FUNC Vec3 lerp(const Vec3 _a, const Vec3 _b, float _t);
 
 	///
-	void vec3Max(float* _result, const float* _a, const float* _b);
+	BX_CONSTEXPR_FUNC Vec3 lerp(const Vec3 _a, const Vec3 _b, const Vec3 _t);
 
 	///
-	void vec3Rcp(float* _result, const float* _a);
+	BX_CONST_FUNC Vec3 normalize(const Vec3 _a);
 
-	/// Calculate tangent frame from normal.
 	///
-	void vec3TangentFrame(const float* _n, float* _t, float* _b);
+	BX_CONSTEXPR_FUNC Vec3 min(const Vec3 _a, const Vec3 _b);
 
-	/// Calculate tangent frame from normal and angle.
 	///
-	void vec3TangentFrame(const float* _n, float* _t, float* _b, float _angle);
+	BX_CONSTEXPR_FUNC Vec3 max(const Vec3 _a, const Vec3 _b);
 
 	///
-	void vec3FromLatLong(float* _vec, float _u, float _v);
+	BX_CONSTEXPR_FUNC Vec3 rcp(const Vec3 _a);
 
-	/// Convert direction to 2D latitude and longitude.
 	///
-	/// @param[out] _outU U-coordinate.
-	/// @param[out] _outV V-coordinate.
-	/// @param[in]  _dir Normalized direction vector.
+	void calcTangentFrame(Vec3& _outT, Vec3& _outB, const Vec3 _n);
+
+	///
+	void calcTangentFrame(Vec3& _outT, Vec3& _outB, const Vec3 _n, float _angle);
+
+	///
+	BX_CONST_FUNC Vec3 fromLatLong(float _u, float _v);
+
+	///
+	void toLatLong(float* _outU, float* _outV, const Vec3 _dir);
+
 	///
-	void vec3ToLatLong(float* _outU, float* _outV, const float* _dir);
+	BX_CONSTEXPR_FUNC Quaternion invert(const Quaternion _a);
 
 	///
-	void quatIdentity(float* _result);
+	BX_CONSTEXPR_FUNC Vec3 mulXyz(const Quaternion _a, const Quaternion _b);
 
 	///
-	void quatMove(float* _result, const float* _a);
+	BX_CONSTEXPR_FUNC Quaternion mul(const Quaternion _a, const Quaternion _b);
 
 	///
-	void quatMulXYZ(float* _result, const float* _qa, const float* _qb);
+	BX_CONSTEXPR_FUNC Vec3 mul(const Vec3 _v, const Quaternion _q);
 
 	///
-	void quatMul(float* _result, const float* _qa, const float* _qb);
+	BX_CONSTEXPR_FUNC float dot(const Quaternion _a, const Quaternion _b);
 
 	///
-	void quatInvert(float* _result, const float* _quat);
+	BX_CONSTEXPR_FUNC Quaternion normalize(const Quaternion _a);
 
 	///
-	float quatDot(const float* _a, const float* _b);
+	BX_CONST_FUNC Vec3 toEuler(const Quaternion _a);
 
 	///
-	void quatNorm(float* _result, const float* _quat);
+	BX_CONST_FUNC Quaternion rotateAxis(const Vec3 _axis, float _angle);
 
 	///
-	void quatToEuler(float* _result, const float* _quat);
+	BX_CONST_FUNC Quaternion rotateX(float _ax);
 
 	///
-	void quatRotateAxis(float* _result, const float* _axis, float _angle);
+	BX_CONST_FUNC Quaternion rotateY(float _ay);
 
 	///
-	void quatRotateX(float* _result, float _ax);
+	BX_CONST_FUNC Quaternion rotateZ(float _az);
 
 	///
-	void quatRotateY(float* _result, float _ay);
+	void vec3Add(float* _result, const float* _a, const float* _b);
 
 	///
-	void quatRotateZ(float* _result, float _az);
+	void vec3Sub(float* _result, const float* _a, const float* _b);
 
 	///
-	void vec3MulQuat(float* _result, const float* _vec, const float* _quat);
+	float vec3Dot(const float* _a, const float* _b);
 
 	///
 	void mtxIdentity(float* _result);
@@ -401,13 +412,13 @@ namespace bx
 	void mtxQuatTranslationHMD(float* _result, const float* _quat, const float* _translation);
 
 	///
-	void mtxLookAtLh(float* _result, const float* _eye, const float* _at, const float* _up = NULL);
+	void mtxLookAtLh(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up = { 0.0f, 1.0f, 0.0f });
 
 	///
-	void mtxLookAtRh(float* _result, const float* _eye, const float* _at, const float* _up = NULL);
+	void mtxLookAtRh(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up = { 0.0f, 1.0f, 0.0f });
 
 	///
-	void mtxLookAt(float* _result, const float* _eye, const float* _at, const float* _up = NULL);
+	void mtxLookAt(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up = { 0.0f, 1.0f, 0.0f });
 
 	///
 	void mtxProj(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, float _far, bool _oglNdc);
@@ -550,10 +561,13 @@ namespace bx
 	void mtxViewFlipHandedness(float* _dst, const float* _src);
 
 	///
-	void calcNormal(float _result[3], float _va[3], float _vb[3], float _vc[3]);
+	void calcNormal(float _result[3], const float _va[3], const float _vb[3], const float _vc[3]);
+
+	///
+	void calcPlane(float _result[4], const float _va[3], const float _vb[3], const float _vc[3]);
 
 	///
-	void calcPlane(float _result[4], float _va[3], float _vb[3], float _vc[3]);
+	void calcPlane(float _result[4], const float _normal[3], const float _pos[3]);
 
 	///
 	void calcLinearFit2D(float _result[2], const void* _points, uint32_t _stride, uint32_t _numPoints);

+ 5 - 7
bx.mod/bx/include/bx/os.h

@@ -7,6 +7,7 @@
 #define BX_OS_H_HEADER_GUARD
 
 #include "debug.h"
+#include "filepath.h"
 
 #if BX_PLATFORM_OSX
 #	define BX_DL_EXT "dylib"
@@ -31,22 +32,19 @@ namespace bx
 	size_t getProcessMemoryUsed();
 
 	///
-	void* dlopen(const char* _filePath);
+	void* dlopen(const FilePath& _filePath);
 
 	///
 	void dlclose(void* _handle);
 
 	///
-	void* dlsym(void* _handle, const char* _symbol);
+	void* dlsym(void* _handle, const StringView& _symbol);
 
 	///
-	bool getenv(const char* _name, char* _out, uint32_t* _inOutSize);
+	bool getEnv(char* _out, uint32_t* _inOutSize, const StringView& _name);
 
 	///
-	void setenv(const char* _name, const char* _value);
-
-	///
-	void unsetenv(const char* _name);
+	void setEnv(const StringView& _name, const StringView& _value);
 
 	///
 	int chdir(const char* _path);

+ 4 - 0
bx.mod/bx/include/bx/pixelformat.h

@@ -41,6 +41,10 @@ namespace bx
 	///
 	float fromSnorm(int32_t _value, float _scale);
 
+	// A8
+	void packA8(void* _dst, const float* _src);
+	void unpackA8(float* _dst, const void* _src);
+
 	// R8
 	void packR8(void* _dst, const float* _src);
 	void unpackR8(float* _dst, const void* _src);

+ 71 - 71
bx.mod/bx/include/bx/platform.h

@@ -11,10 +11,10 @@
 #define BX_ARCH_64BIT 0
 
 // Compiler
-#define BX_COMPILER_CLANG           0
-#define BX_COMPILER_CLANG_ANALYZER  0
-#define BX_COMPILER_GCC             0
-#define BX_COMPILER_MSVC            0
+#define BX_COMPILER_CLANG          0
+#define BX_COMPILER_CLANG_ANALYZER 0
+#define BX_COMPILER_GCC            0
+#define BX_COMPILER_MSVC           0
 
 // Endianess
 #define BX_CPU_ENDIAN_BIG    0
@@ -80,34 +80,34 @@
 #endif //
 
 // http://sourceforge.net/apps/mediawiki/predef/index.php?title=Architectures
-#if defined(__arm__)     || \
-	defined(__aarch64__) || \
-	defined(_M_ARM)
+#if defined(__arm__)     \
+ || defined(__aarch64__) \
+ || defined(_M_ARM)
 #	undef  BX_CPU_ARM
 #	define BX_CPU_ARM 1
 #	define BX_CACHE_LINE_SIZE 64
-#elif defined(__MIPSEL__)     || \
-	  defined(__mips_isa_rev) || \
-	  defined(__mips64)
+#elif defined(__MIPSEL__)     \
+ ||   defined(__mips_isa_rev) \
+ ||   defined(__mips64)
 #	undef  BX_CPU_MIPS
 #	define BX_CPU_MIPS 1
 #	define BX_CACHE_LINE_SIZE 64
-#elif defined(_M_PPC)        || \
-	  defined(__powerpc__)   || \
-	  defined(__powerpc64__)
+#elif defined(_M_PPC)        \
+ ||   defined(__powerpc__)   \
+ ||   defined(__powerpc64__)
 #	undef  BX_CPU_PPC
 #	define BX_CPU_PPC 1
 #	define BX_CACHE_LINE_SIZE 128
-#elif defined(__riscv)   || \
-	  defined(__riscv__) || \
-	  defined(RISCVEL)
+#elif defined(__riscv)   \
+ ||   defined(__riscv__) \
+ ||   defined(RISCVEL)
 #	undef  BX_CPU_RISCV
 #	define BX_CPU_RISCV 1
 #	define BX_CACHE_LINE_SIZE 64
-#elif defined(_M_IX86)    || \
-	  defined(_M_X64)     || \
-	  defined(__i386__)   || \
-	  defined(__x86_64__)
+#elif defined(_M_IX86)    \
+ ||   defined(_M_X64)     \
+ ||   defined(__i386__)   \
+ ||   defined(__x86_64__)
 #	undef  BX_CPU_X86
 #	define BX_CPU_X86 1
 #	define BX_CACHE_LINE_SIZE 64
@@ -117,14 +117,14 @@
 #	define BX_CACHE_LINE_SIZE 64
 #endif //
 
-#if defined(__x86_64__)    || \
-	defined(_M_X64)        || \
-	defined(__aarch64__)   || \
-	defined(__64BIT__)     || \
-	defined(__mips64)      || \
-	defined(__powerpc64__) || \
-	defined(__ppc64__)     || \
-	defined(__LP64__)
+#if defined(__x86_64__)    \
+ || defined(_M_X64)        \
+ || defined(__aarch64__)   \
+ || defined(__64BIT__)     \
+ || defined(__mips64)      \
+ || defined(__powerpc64__) \
+ || defined(__ppc64__)     \
+ || defined(__LP64__)
 #	undef  BX_ARCH_64BIT
 #	define BX_ARCH_64BIT 64
 #else
@@ -211,8 +211,8 @@
 #	undef  BX_PLATFORM_HURD
 #	define BX_PLATFORM_HURD 1
 #elif defined(__NX__)
-# undef BX_PLATFORM_NX
-# define BX_PLATFORM_NX 1
+#	undef  BX_PLATFORM_NX
+#	define BX_PLATFORM_NX 1
 #endif //
 
 #if !BX_CRT_NONE
@@ -246,47 +246,47 @@
 #	endif // BX_CRT_*
 #endif // !BX_CRT_NONE
 
-#define BX_PLATFORM_POSIX (0      \
-		|| BX_PLATFORM_ANDROID    \
-		|| BX_PLATFORM_BSD        \
-		|| BX_PLATFORM_EMSCRIPTEN \
-		|| BX_PLATFORM_HURD       \
-		|| BX_PLATFORM_IOS        \
-		|| BX_PLATFORM_LINUX      \
-		|| BX_PLATFORM_NX         \
-		|| BX_PLATFORM_OSX        \
-		|| BX_PLATFORM_PS4        \
-		|| BX_PLATFORM_RPI        \
-		|| BX_PLATFORM_STEAMLINK  \
-		)
+#define BX_PLATFORM_POSIX (0   \
+	||  BX_PLATFORM_ANDROID    \
+	||  BX_PLATFORM_BSD        \
+	||  BX_PLATFORM_EMSCRIPTEN \
+	||  BX_PLATFORM_HURD       \
+	||  BX_PLATFORM_IOS        \
+	||  BX_PLATFORM_LINUX      \
+	||  BX_PLATFORM_NX         \
+	||  BX_PLATFORM_OSX        \
+	||  BX_PLATFORM_PS4        \
+	||  BX_PLATFORM_RPI        \
+	||  BX_PLATFORM_STEAMLINK  \
+	)
 
-#define BX_PLATFORM_NONE !(0      \
-		|| BX_PLATFORM_ANDROID    \
-		|| BX_PLATFORM_BSD        \
-		|| BX_PLATFORM_EMSCRIPTEN \
-		|| BX_PLATFORM_HURD       \
-		|| BX_PLATFORM_IOS        \
-		|| BX_PLATFORM_LINUX      \
-		|| BX_PLATFORM_NX         \
-		|| BX_PLATFORM_OSX        \
-		|| BX_PLATFORM_PS4        \
-		|| BX_PLATFORM_RPI        \
-		|| BX_PLATFORM_STEAMLINK  \
-		|| BX_PLATFORM_WINDOWS    \
-		|| BX_PLATFORM_WINRT      \
-		|| BX_PLATFORM_XBOXONE    \
-		)
+#define BX_PLATFORM_NONE !(0   \
+	||  BX_PLATFORM_ANDROID    \
+	||  BX_PLATFORM_BSD        \
+	||  BX_PLATFORM_EMSCRIPTEN \
+	||  BX_PLATFORM_HURD       \
+	||  BX_PLATFORM_IOS        \
+	||  BX_PLATFORM_LINUX      \
+	||  BX_PLATFORM_NX         \
+	||  BX_PLATFORM_OSX        \
+	||  BX_PLATFORM_PS4        \
+	||  BX_PLATFORM_RPI        \
+	||  BX_PLATFORM_STEAMLINK  \
+	||  BX_PLATFORM_WINDOWS    \
+	||  BX_PLATFORM_WINRT      \
+	||  BX_PLATFORM_XBOXONE    \
+	)
 
 #if BX_COMPILER_GCC
-#	define BX_COMPILER_NAME "GCC " \
-				BX_STRINGIZE(__GNUC__) "." \
-				BX_STRINGIZE(__GNUC_MINOR__) "." \
-				BX_STRINGIZE(__GNUC_PATCHLEVEL__)
+#	define BX_COMPILER_NAME "GCC "       \
+		BX_STRINGIZE(__GNUC__) "."       \
+		BX_STRINGIZE(__GNUC_MINOR__) "." \
+		BX_STRINGIZE(__GNUC_PATCHLEVEL__)
 #elif BX_COMPILER_CLANG
-#	define BX_COMPILER_NAME "Clang " \
-				BX_STRINGIZE(__clang_major__) "." \
-				BX_STRINGIZE(__clang_minor__) "." \
-				BX_STRINGIZE(__clang_patchlevel__)
+#	define BX_COMPILER_NAME "Clang "      \
+		BX_STRINGIZE(__clang_major__) "." \
+		BX_STRINGIZE(__clang_minor__) "." \
+		BX_STRINGIZE(__clang_patchlevel__)
 #elif BX_COMPILER_MSVC
 #	if BX_COMPILER_MSVC >= 1910 // Visual Studio 2017
 #		define BX_COMPILER_NAME "MSVC 15.0"
@@ -311,10 +311,10 @@
 #elif BX_PLATFORM_BSD
 #	define BX_PLATFORM_NAME "BSD"
 #elif BX_PLATFORM_EMSCRIPTEN
-#	define BX_PLATFORM_NAME "asm.js " \
-				BX_STRINGIZE(__EMSCRIPTEN_major__) "." \
-				BX_STRINGIZE(__EMSCRIPTEN_minor__) "." \
-				BX_STRINGIZE(__EMSCRIPTEN_tiny__)
+#	define BX_PLATFORM_NAME "asm.js "          \
+		BX_STRINGIZE(__EMSCRIPTEN_major__) "." \
+		BX_STRINGIZE(__EMSCRIPTEN_minor__) "." \
+		BX_STRINGIZE(__EMSCRIPTEN_tiny__)
 #elif BX_PLATFORM_HURD
 #	define BX_PLATFORM_NAME "Hurd"
 #elif BX_PLATFORM_IOS

+ 7 - 7
bx.mod/bx/include/bx/readerwriter.h

@@ -262,7 +262,13 @@ namespace bx
 	/// Write string view.
 	int32_t write(WriterI* _writer, const StringView& _str, Error* _err = NULL);
 
-	///
+	/// Write formated string.
+	int32_t write(WriterI* _writer, const StringView& _format, va_list _argList, Error* _err);
+
+	/// Write formated string.
+	int32_t write(WriterI* _writer, Error* _err, const StringView* _format, ...);
+
+	/// Write formated string.
 	int32_t write(WriterI* _writer, Error* _err, const char* _format, ...);
 
 	/// Write repeat the same value.
@@ -280,12 +286,6 @@ namespace bx
 	template<typename Ty>
 	int32_t writeBE(WriterI* _writer, const Ty& _value, Error* _err = NULL);
 
-	/// Write formated string.
-	int32_t writePrintfVargs(WriterI* _writer, const char* _format, va_list _argList);
-
-	/// Write formated string.
-	int32_t writePrintf(WriterI* _writer, const char* _format, ...);
-
 	/// Skip _offset bytes forward.
 	int64_t skip(SeekerI* _seeker, int64_t _offset);
 

+ 3 - 3
bx.mod/bx/include/bx/rng.h

@@ -57,15 +57,15 @@ namespace bx
 
 	/// Generate random point on unit circle.
 	template <typename Rng>
-	void randUnitCircle(float _result[3], Rng* _rng);
+	bx::Vec3 randUnitCircle(Rng* _rng);
 
 	/// Generate random point on unit sphere.
 	template <typename Rng>
-	void randUnitSphere(float _result[3], Rng* _rng);
+	bx::Vec3 randUnitSphere(Rng* _rng);
 
 	/// Generate random point on unit hemisphere.
 	template <typename Ty>
-	void randUnitHemisphere(float _result[3], Ty* _rng, const float _normal[3]);
+	bx::Vec3 randUnitHemisphere(Ty* _rng, const bx::Vec3& _normal);
 
 	/// Sampling with Hammersley and Halton Points
 	/// http://www.cse.cuhk.edu.hk/~ttwong/papers/udpoint/udpoints.html

+ 1 - 1
bx.mod/bx/include/bx/settings.h

@@ -29,7 +29,7 @@ namespace bx
 		void load(const void* _data, uint32_t _len);
 
 		///
-		const char* get(const StringView& _name) const;
+		StringView get(const StringView& _name) const;
 
 		///
 		void set(const StringView& _name, const StringView& _value = "");

+ 42 - 27
bx.mod/bx/include/bx/string.h

@@ -28,7 +28,7 @@ namespace bx
 		StringView();
 
 		///
-		StringView(const StringView& _rhs);
+		StringView(const StringView& _rhs, int32_t _start = 0, int32_t _len = INT32_MAX);
 
 		///
 		StringView& operator=(const char* _rhs);
@@ -37,7 +37,16 @@ namespace bx
 		StringView& operator=(const StringView& _rhs);
 
 		///
-		StringView(const char* _ptr, int32_t _len = INT32_MAX);
+		StringView(char* _ptr);
+
+		///
+		StringView(const char* _ptr);
+
+		///
+		StringView(char* _ptr, int32_t _len);
+
+		///
+		StringView(const char* _ptr, int32_t _len);
 
 		///
 		StringView(const char* _ptr, const char* _term);
@@ -47,13 +56,19 @@ namespace bx
 		explicit StringView(const Ty& _container);
 
 		///
-		void set(const char* _ptr, int32_t _len = INT32_MAX);
+		void set(char* _ptr);
+
+		///
+		void set(const char* _ptr);
+
+		///
+		void set(const char* _ptr, int32_t _len);
 
 		///
 		void set(const char* _ptr, const char* _term);
 
 		///
-		void set(const StringView& _str);
+		void set(const StringView& _str, int32_t _start = 0, int32_t _len = INT32_MAX);
 
 		///
 		template<typename Ty>
@@ -198,20 +213,26 @@ namespace bx
 	int32_t strCat(char* _dst, int32_t _dstSize, const StringView& _str, int32_t _num = INT32_MAX);
 
 	/// Find character in string. Limit search to _max characters.
-	const char* strFind(const StringView& _str, char _ch);
+	StringView strFind(const StringView& _str, char _ch);
 
 	/// Find character in string in reverse. Limit search to _max characters.
-	const char* strRFind(const StringView& _str, char _ch);
+	StringView strRFind(const StringView& _str, char _ch);
 
 	/// Find substring in string. Limit search to _max characters.
-	const char* strFind(const StringView& _str, const StringView& _find, int32_t _num = INT32_MAX);
+	StringView strFind(const StringView& _str, const StringView& _find, int32_t _num = INT32_MAX);
 
 	/// Find substring in string. Case insensitive. Limit search to _max characters.
-	const char* strFindI(const StringView& _str, const StringView& _find, int32_t _num = INT32_MAX);
+	StringView strFindI(const StringView& _str, const StringView& _find, int32_t _num = INT32_MAX);
 
 	/// Returns string view with characters _chars trimmed from left.
 	StringView strLTrim(const StringView& _str, const StringView& _chars);
 
+	/// Returns string view with whitespace characters trimmed from left.
+	StringView strLTrimSpace(const StringView& _str);
+
+	/// Returns string view with non-whitespace characters trimmed from left.
+	StringView strLTrimNonSpace(const StringView& _str);
+
 	/// Returns string view with characters _chars trimmed from right.
 	StringView strRTrim(const StringView& _str, const StringView& _chars);
 
@@ -219,34 +240,28 @@ namespace bx
 	StringView strTrim(const StringView& _str, const StringView& _chars);
 
 	/// Find new line. Returns pointer after new line terminator.
-	const char* strnl(const char* _str);
+	StringView strFindNl(const StringView& _str);
 
 	/// Find end of line. Retuns pointer to new line terminator.
-	const char* streol(const char* _str);
-
-	/// Skip whitespace.
-	const char* strws(const char* _str);
-
-	/// Skip non-whitespace.
-	const char* strnws(const char* _str);
-
-	/// Returns pointer to first character after word.
-	const char* strSkipWord(const char* _str, int32_t _max = INT32_MAX);
+	StringView strFindEol(const StringView& _str);
 
 	/// Returns StringView of word or empty.
 	StringView strWord(const StringView& _str);
 
+	/// Returns substring in string.
+	StringView strSubstr(const StringView& _str, int32_t _start, int32_t _len = INT32_MAX);
+
 	/// Find matching block.
-	const char* strmb(const char* _str, char _open, char _close);
+	StringView strFindBlock(const StringView& _str, char _open, char _close);
 
 	// Normalize string to sane line endings.
-	void eolLF(char* _out, int32_t _size, const char* _str);
+	StringView normalizeEolLf(char* _out, int32_t _size, const StringView& _str);
 
 	// Finds identifier.
-	const char* findIdentifierMatch(const char* _str, const char* _word);
+	StringView findIdentifierMatch(const StringView& _str, const StringView& _word);
 
 	/// Finds any identifier from NULL terminated array of identifiers.
-	const char* findIdentifierMatch(const char* _str, const char* _words[]);
+	StringView findIdentifierMatch(const StringView& _str, const char** _words);
 
 	/// Cross platform implementation of vsnprintf that returns number of
 	/// characters which would have been written to the final string if
@@ -280,16 +295,16 @@ namespace bx
 	int32_t toString(char* _out, int32_t _max, double _value);
 
 	/// Converts 32-bit integer value to string.
-	int32_t toString(char* _out, int32_t _max, int32_t _value, uint32_t _base = 10);
+	int32_t toString(char* _out, int32_t _max, int32_t _value, uint32_t _base = 10, char _separator = '\0');
 
 	/// Converts 64-bit integer value to string.
-	int32_t toString(char* _out, int32_t _max, int64_t _value, uint32_t _base = 10);
+	int32_t toString(char* _out, int32_t _max, int64_t _value, uint32_t _base = 10, char _separator = '\0');
 
 	/// Converts 32-bit unsigned integer value to string.
-	int32_t toString(char* _out, int32_t _max, uint32_t _value, uint32_t _base = 10);
+	int32_t toString(char* _out, int32_t _max, uint32_t _value, uint32_t _base = 10, char _separator = '\0');
 
 	/// Converts 64-bit unsigned integer value to string.
-	int32_t toString(char* _out, int32_t _max, uint64_t _value, uint32_t _base = 10);
+	int32_t toString(char* _out, int32_t _max, uint64_t _value, uint32_t _base = 10, char _separator = '\0');
 
 	/// Converts string to bool value.
 	bool fromString(bool* _out, const StringView& _str);

+ 79 - 129
bx.mod/bx/include/bx/uint32_t.h

@@ -8,280 +8,230 @@
 
 #include "bx.h"
 
-#if BX_COMPILER_MSVC
-#	if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT
-#		include <intrin.h>
-#		pragma intrinsic(_BitScanForward)
-#		pragma intrinsic(_BitScanReverse)
-#		if BX_ARCH_64BIT
-#			pragma intrinsic(_BitScanForward64)
-#			pragma intrinsic(_BitScanReverse64)
-#		endif // BX_ARCH_64BIT
-#	endif // BX_PLATFORM_WINDOWS
-#endif // BX_COMPILER_MSVC
-
-#define BX_HALF_FLOAT_ZERO UINT16_C(0)
-#define BX_HALF_FLOAT_HALF UINT16_C(0x3800)
-#define BX_HALF_FLOAT_ONE  UINT16_C(0x3c00)
-#define BX_HALF_FLOAT_TWO  UINT16_C(0x4000)
-
 namespace bx
 {
-	///
-	uint32_t uint32_li(uint32_t _a);
+	constexpr uint16_t kHalfFloatZero = UINT16_C(0);
+	constexpr uint16_t kHalfFloatHalf = UINT16_C(0x3800);
+	constexpr uint16_t kHalfFloatOne  = UINT16_C(0x3c00);
+	constexpr uint16_t kHalfFloatTwo  = UINT16_C(0x4000);
 
 	///
-	uint32_t uint32_dec(uint32_t _a);
+	BX_CONSTEXPR_FUNC uint32_t uint32_li(uint32_t _a);
 
 	///
-	uint32_t uint32_inc(uint32_t _a);
+	BX_CONSTEXPR_FUNC uint32_t uint32_dec(uint32_t _a);
 
 	///
-	uint32_t uint32_not(uint32_t _a);
+	BX_CONSTEXPR_FUNC uint32_t uint32_inc(uint32_t _a);
 
 	///
-	uint32_t uint32_neg(uint32_t _a);
+	BX_CONSTEXPR_FUNC uint32_t uint32_not(uint32_t _a);
 
 	///
-	uint32_t uint32_ext(uint32_t _a);
+	BX_CONSTEXPR_FUNC uint32_t uint32_neg(uint32_t _a);
 
 	///
-	uint32_t uint32_and(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_ext(uint32_t _a);
 
 	///
-	uint32_t uint32_andc(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_and(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_xor(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_andc(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_xorl(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_xor(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_or(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_xorl(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_orc(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_or(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_sll(uint32_t _a, int _sa);
+	BX_CONSTEXPR_FUNC uint32_t uint32_orc(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_srl(uint32_t _a, int _sa);
+	BX_CONSTEXPR_FUNC uint32_t uint32_sll(uint32_t _a, int32_t _sa);
 
 	///
-	uint32_t uint32_sra(uint32_t _a, int _sa);
+	BX_CONSTEXPR_FUNC uint32_t uint32_srl(uint32_t _a, int32_t _sa);
 
 	///
-	uint32_t uint32_rol(uint32_t _a, int _sa);
+	BX_CONSTEXPR_FUNC uint32_t uint32_sra(uint32_t _a, int32_t _sa);
 
 	///
-	uint32_t uint32_ror(uint32_t _a, int _sa);
+	BX_CONSTEXPR_FUNC uint32_t uint32_rol(uint32_t _a, int32_t _sa);
 
 	///
-	uint32_t uint32_add(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_ror(uint32_t _a, int32_t _sa);
 
 	///
-	uint32_t uint32_sub(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_add(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_mul(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_sub(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_div(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_mul(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_mod(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_div(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_cmpeq(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_mod(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_cmpneq(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_cmpeq(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_cmplt(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_cmpneq(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_cmple(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_cmplt(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_cmpgt(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_cmple(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_cmpge(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_cmpgt(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_setnz(uint32_t _a);
+	BX_CONSTEXPR_FUNC uint32_t uint32_cmpge(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_satadd(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_setnz(uint32_t _a);
 
 	///
-	uint32_t uint32_satsub(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_satadd(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_satmul(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_satsub(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_sels(uint32_t test, uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_satmul(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_selb(uint32_t _mask, uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_sels(uint32_t test, uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_imin(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_selb(uint32_t _mask, uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_imax(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_imin(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_min(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_imax(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_min(uint32_t _a, uint32_t _b, uint32_t _c);
+	BX_CONSTEXPR_FUNC uint32_t uint32_min(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_max(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_min(uint32_t _a, uint32_t _b, uint32_t _c);
 
 	///
-	uint32_t uint32_max(uint32_t _a, uint32_t _b, uint32_t _c);
+	BX_CONSTEXPR_FUNC uint32_t uint32_max(uint32_t _a, uint32_t _b);
 
 	///
-	uint32_t uint32_clamp(uint32_t _a, uint32_t _min, uint32_t _max);
+	BX_CONSTEXPR_FUNC uint32_t uint32_max(uint32_t _a, uint32_t _b, uint32_t _c);
 
 	///
-	uint32_t uint32_iclamp(uint32_t _a, uint32_t _min, uint32_t _max);
+	BX_CONSTEXPR_FUNC uint32_t uint32_clamp(uint32_t _a, uint32_t _min, uint32_t _max);
 
 	///
-	uint32_t uint32_incwrap(uint32_t _val, uint32_t _min, uint32_t _max);
+	BX_CONSTEXPR_FUNC uint32_t uint32_iclamp(uint32_t _a, uint32_t _min, uint32_t _max);
 
 	///
-	uint32_t uint32_decwrap(uint32_t _val, uint32_t _min, uint32_t _max);
+	BX_CONSTEXPR_FUNC uint32_t uint32_incwrap(uint32_t _val, uint32_t _min, uint32_t _max);
 
 	///
-	uint32_t uint32_cntbits_ref(uint32_t _val);
+	BX_CONSTEXPR_FUNC uint32_t uint32_decwrap(uint32_t _val, uint32_t _min, uint32_t _max);
 
 	/// Count number of bits set.
 	///
-	uint32_t uint32_cntbits(uint32_t _val);
-
-	///
-	uint32_t uint32_cntlz_ref(uint32_t _val);
+	BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(uint32_t _val);
 
 	/// Count number of leading zeros.
 	///
-	uint32_t uint32_cntlz(uint32_t _val);
-
-	///
-	uint32_t uint32_cnttz_ref(uint32_t _val);
-
-	///
-	uint32_t uint32_cnttz(uint32_t _val);
-
-	// shuffle:
-	// ---- ---- ---- ---- fedc ba98 7654 3210
-	// to:
-	// -f-e -d-c -b-a -9-8 -7-6 -5-4 -3-2 -1-0
-	uint32_t uint32_part1by1(uint32_t _a);
-
-	// shuffle:
-	// ---- ---- ---- ---- ---- --98 7654 3210
-	// to:
-	// ---- 9--8 --7- -6-- 5--4 --3- -2-- 1--0
-	///
-	uint32_t uint32_part1by2(uint32_t _a);
-
-	///
-	uint32_t uint32_testpow2(uint32_t _a);
-
-	///
-	uint32_t uint32_nextpow2(uint32_t _a);
+	BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(uint32_t _val);
 
 	///
-	uint16_t halfFromFloat(float _a);
+	BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(uint32_t _val);
 
 	///
-	float halfToFloat(uint16_t _a);
+	BX_CONSTEXPR_FUNC uint32_t uint32_part1by1(uint32_t _a);
 
 	///
-	uint16_t uint16_min(uint16_t _a, uint16_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_part1by2(uint32_t _a);
 
 	///
-	uint16_t uint16_max(uint16_t _a, uint16_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_testpow2(uint32_t _a);
 
 	///
-	int64_t int64_min(int64_t _a, int64_t _b);
-
-	///
-	int64_t int64_max(int64_t _a, int64_t _b);
-
-	///
-	int64_t int64_clamp(int64_t _a, int64_t _min, int64_t _max);
-
-	///
-	uint32_t uint64_cntbits_ref(uint64_t _val);
+	BX_CONSTEXPR_FUNC uint32_t uint32_nextpow2(uint32_t _a);
 
 	/// Count number of bits set.
 	///
-	uint32_t uint64_cntbits(uint64_t _val);
-
-	///
-	uint32_t uint64_cntlz_ref(uint64_t _val);
+	BX_CONSTEXPR_FUNC uint32_t uint64_cntbits(uint64_t _val);
 
 	/// Count number of leading zeros.
 	///
-	uint32_t uint64_cntlz(uint64_t _val);
-
-	///
-	uint32_t uint64_cnttz_ref(uint64_t _val);
+	BX_CONSTEXPR_FUNC uint32_t uint64_cntlz(uint64_t _val);
 
 	///
-	uint32_t uint64_cnttz(uint64_t _val);
+	BX_CONSTEXPR_FUNC uint32_t uint64_cnttz(uint64_t _val);
 
 	///
-	uint64_t uint64_sll(uint64_t _a, int _sa);
+	BX_CONSTEXPR_FUNC uint64_t uint64_sll(uint64_t _a, int32_t _sa);
 
 	///
-	uint64_t uint64_srl(uint64_t _a, int _sa);
+	BX_CONSTEXPR_FUNC uint64_t uint64_srl(uint64_t _a, int32_t _sa);
 
 	///
-	uint64_t uint64_sra(uint64_t _a, int _sa);
+	BX_CONSTEXPR_FUNC uint64_t uint64_sra(uint64_t _a, int32_t _sa);
 
 	///
-	uint64_t uint64_rol(uint64_t _a, int _sa);
+	BX_CONSTEXPR_FUNC uint64_t uint64_rol(uint64_t _a, int32_t _sa);
 
 	///
-	uint64_t uint64_ror(uint64_t _a, int _sa);
+	BX_CONSTEXPR_FUNC uint64_t uint64_ror(uint64_t _a, int32_t _sa);
 
 	///
-	uint64_t uint64_add(uint64_t _a, uint64_t _b);
+	BX_CONSTEXPR_FUNC uint64_t uint64_add(uint64_t _a, uint64_t _b);
 
 	///
-	uint64_t uint64_sub(uint64_t _a, uint64_t _b);
+	BX_CONSTEXPR_FUNC uint64_t uint64_sub(uint64_t _a, uint64_t _b);
 
 	///
-	uint64_t uint64_mul(uint64_t _a, uint64_t _b);
+	BX_CONSTEXPR_FUNC uint64_t uint64_mul(uint64_t _a, uint64_t _b);
 
 	/// Greatest common divisor.
 	///
-	uint32_t uint32_gcd(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_gcd(uint32_t _a, uint32_t _b);
 
 	/// Least common multiple.
 	///
-	uint32_t uint32_lcm(uint32_t _a, uint32_t _b);
+	BX_CONSTEXPR_FUNC uint32_t uint32_lcm(uint32_t _a, uint32_t _b);
 
 	/// Align to arbitrary stride.
 	///
-	uint32_t strideAlign(uint32_t _offset, uint32_t _stride);
+	BX_CONSTEXPR_FUNC uint32_t strideAlign(uint32_t _offset, uint32_t _stride);
 
 	/// Align to arbitrary stride and 16-bytes.
 	///
-	uint32_t strideAlign16(uint32_t _offset, uint32_t _stride);
+	BX_CONSTEXPR_FUNC uint32_t strideAlign16(uint32_t _offset, uint32_t _stride);
 
 	/// Align to arbitrary stride and 256-bytes.
 	///
-	uint32_t strideAlign256(uint32_t _offset, uint32_t _stride);
+	BX_CONSTEXPR_FUNC uint32_t strideAlign256(uint32_t _offset, uint32_t _stride);
+
+	/// Convert float to half-float.
+	///
+	BX_CONST_FUNC uint16_t halfFromFloat(float _a);
+
+	/// Convert half-float to float.
+	///
+	BX_CONST_FUNC float halfToFloat(uint16_t _a);
 
 } // namespace bx
 

+ 4 - 8
bx.mod/bx/makefile

@@ -6,8 +6,7 @@
 GENIE=../bx/tools/bin/$(OS)/genie
 
 all:
-	$(GENIE) vs2012
-	$(GENIE) vs2013
+	$(GENIE) vs2017
 	$(GENIE) --gcc=android-arm gmake
 	$(GENIE) --gcc=android-mips gmake
 	$(GENIE) --gcc=android-x86 gmake
@@ -17,7 +16,7 @@ all:
 	$(GENIE) --gcc=ios-arm gmake
 	$(GENIE) --gcc=ios-simulator gmake
 	$(GENIE) --gcc=ios-simulator64 gmake
-	$(GENIE) xcode4
+	$(GENIE) xcode8
 
 .build/projects/gmake-android-arm:
 	$(GENIE) --gcc=android-arm gmake
@@ -75,11 +74,8 @@ mingw-clang-release64: .build/projects/gmake-mingw-clang
 	make -R -C .build/projects/gmake-mingw-clang config=release64
 mingw-clang: mingw-clang-debug32 mingw-clang-release32 mingw-clang-debug64 mingw-clang-release64
 
-.build/projects/vs2012:
-	$(GENIE) vs2012
-
-.build/projects/vs2013:
-	$(GENIE) vs2013
+.build/projects/vs2017:
+	$(GENIE) vs2017
 
 .build/projects/gmake-osx:
 	$(GENIE) --gcc=osx gmake

+ 1 - 0
bx.mod/bx/scripts/lemon.lua

@@ -12,6 +12,7 @@ project "lemon"
 
 	configuration { "not vs*" }
 		buildoptions {
+			"-Wno-implicit-fallthrough",
 			"-Wno-sign-compare",
 			"-Wno-unused-parameter",
 		}

+ 63 - 65
bx.mod/bx/scripts/toolchain.lua

@@ -50,7 +50,6 @@ function toolchain(_buildDir, _libDir)
 		description = "Choose GCC flavor",
 		allowed = {
 			{ "android-arm",     "Android - ARM"              },
-			{ "android-mips",    "Android - MIPS"             },
 			{ "android-x86",     "Android - x86"              },
 			{ "asmjs",           "Emscripten/asm.js"          },
 			{ "freebsd",         "FreeBSD"                    },
@@ -194,7 +193,6 @@ function toolchain(_buildDir, _libDir)
 	end
 
 	flags {
-		"Cpp11",
 		"ExtraWarnings",
 	}
 
@@ -220,25 +218,12 @@ function toolchain(_buildDir, _libDir)
 			premake.gcc.llvm = true
 			location (path.join(_buildDir, "projects", _ACTION .. "-android-arm"))
 
-		elseif "android-mips" == _OPTIONS["gcc"] then
-
-			if not os.getenv("ANDROID_NDK_MIPS")
-			or not os.getenv("ANDROID_NDK_CLANG")
-			or not os.getenv("ANDROID_NDK_ROOT") then
-				print("Set ANDROID_NDK_CLANG, ANDROID_NDK_ARM, and ANDROID_NDK_ROOT environment variables.")
-			end
-
-			premake.gcc.cc   = "$(ANDROID_NDK_CLANG)/bin/clang"
-			premake.gcc.cxx  = "$(ANDROID_NDK_CLANG)/bin/clang++"
-			premake.gcc.llvm = true
-			location (path.join(_buildDir, "projects", _ACTION .. "-android-mips"))
-
 		elseif "android-x86" == _OPTIONS["gcc"] then
 
 			if not os.getenv("ANDROID_NDK_X86")
 			or not os.getenv("ANDROID_NDK_CLANG")
 			or not os.getenv("ANDROID_NDK_ROOT") then
-				print("Set ANDROID_NDK_CLANG, ANDROID_NDK_ARM, and ANDROID_NDK_ROOT environment variables.")
+				print("Set ANDROID_NDK_CLANG, ANDROID_NDK_X86, and ANDROID_NDK_ROOT environment variables.")
 			end
 
 			premake.gcc.cc   = "$(ANDROID_NDK_CLANG)/bin/clang"
@@ -396,9 +381,9 @@ function toolchain(_buildDir, _libDir)
 			location (path.join(_buildDir, "projects", _ACTION .. "-rpi"))
 
 		elseif "riscv" == _OPTIONS["gcc"] then
-			premake.gcc.cc  = "$(FREEDOM_E_SDK)/toolchain/bin/riscv32-unknown-elf-gcc"
-			premake.gcc.cxx = "$(FREEDOM_E_SDK)/toolchain/bin/riscv32-unknown-elf-g++"
-			premake.gcc.ar  = "$(FREEDOM_E_SDK)/toolchain/bin/riscv32-unknown-elf-ar"
+			premake.gcc.cc  = "$(FREEDOM_E_SDK)/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/bin/riscv64-unknown-elf-gcc"
+			premake.gcc.cxx = "$(FREEDOM_E_SDK)/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/bin/riscv64-unknown-elf-g++"
+			premake.gcc.ar  = "$(FREEDOM_E_SDK)/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/bin/riscv64-unknown-elf-ar"
 			location (path.join(_buildDir, "projects", _ACTION .. "-riscv"))
 
 		end
@@ -465,7 +450,9 @@ function toolchain(_buildDir, _libDir)
 
 		end
 
-	elseif _ACTION == "xcode4" then
+	elseif _ACTION == "xcode4"
+		or _ACTION == "xcode8"
+		or _ACTION == "xcode9" then
 		local action = premake.action.current()
 		local str_or = function(str, def)
 			return #str > 0 and str or def
@@ -549,6 +536,7 @@ function toolchain(_buildDir, _libDir)
 			"_WIN32",
 			"_HAS_EXCEPTIONS=0",
 			"_HAS_ITERATOR_DEBUGGING=0",
+			"_ITERATOR_DEBUG_LEVEL=0",
 			"_SCL_SECURE=0",
 			"_SECURE_SCL=0",
 			"_SCL_SECURE_NO_WARNINGS",
@@ -645,6 +633,9 @@ function toolchain(_buildDir, _libDir)
 			"-Wunused-value",
 			"-Wundef",
 		}
+		buildoptions_cpp {
+			"-std=c++14",
+		}
 		linkoptions {
 			"-Wl,--gc-sections",
 			"-static",
@@ -725,13 +716,15 @@ function toolchain(_buildDir, _libDir)
 --			"-Wduplicated-branches",
 --			"-Wduplicated-cond",
 --			"-Wjump-misses-init",
-			"-Wlogical-op",
 			"-Wshadow",
 --			"-Wnull-dereference",
 			"-Wunused-value",
 			"-Wundef",
 --			"-Wuseless-cast",
 		}
+		buildoptions_cpp {
+			"-std=c++14",
+		}
 		links {
 			"rt",
 			"dl",
@@ -741,6 +734,11 @@ function toolchain(_buildDir, _libDir)
 			"-Wl,--as-needed",
 		}
 
+	configuration { "linux-gcc*" }
+		buildoptions {
+			"-Wlogical-op",
+		}
+
 	configuration { "linux-gcc*", "x32" }
 		targetdir (path.join(_buildDir, "linux32_gcc/bin"))
 		objdir (path.join(_buildDir, "linux32_gcc/obj"))
@@ -781,6 +779,9 @@ function toolchain(_buildDir, _libDir)
 			"-Wunused-value",
 			"-Wundef",
 		}
+		buildoptions_cpp {
+			"-std=c++14",
+		}
 		links {
 			"rt",
 			"dl",
@@ -797,6 +798,9 @@ function toolchain(_buildDir, _libDir)
 			"-Wunused-value",
 			"-Wundef",
 		}
+		buildoptions_cpp {
+			"-std=c++14",
+		}
 		links {
 			"rt",
 			"dl",
@@ -812,6 +816,7 @@ function toolchain(_buildDir, _libDir)
 		}
 		includedirs {
 			"$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/include",
+			"${ANDROID_NDK_ROOT}/sysroot/usr/include",
 			"$(ANDROID_NDK_ROOT)/sources/android/native_app_glue",
 		}
 		linkoptions {
@@ -823,7 +828,7 @@ function toolchain(_buildDir, _libDir)
 			"m",
 			"android",
 			"log",
-			"c++",
+			"c++_shared",
 			"gcc",
 		}
 		buildoptions {
@@ -835,6 +840,9 @@ function toolchain(_buildDir, _libDir)
 			"-Wunused-value",
 			"-Wundef",
 		}
+		buildoptions_cpp {
+			"-std=c++14",
+		}
 		linkoptions {
 			"-no-canonical-prefixes",
 			"-Wl,--no-undefined",
@@ -852,6 +860,7 @@ function toolchain(_buildDir, _libDir)
 			"__STEAMLINK__=1", -- There is no special prefedined compiler symbol to detect SteamLink, faking it.
 		}
 		buildoptions {
+			"-std=c++14",
 			"-Wfatal-errors",
 			"-Wunused-value",
 			"-Wundef",
@@ -870,12 +879,10 @@ function toolchain(_buildDir, _libDir)
 		targetdir (path.join(_buildDir, "android-arm/bin"))
 		objdir (path.join(_buildDir, "android-arm/obj"))
 		libdirs {
-			path.join(_libDir, "lib/android-arm"),
 			"$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a",
 		}
 		includedirs {
-			"$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/include",
-			"$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/include",
+			"$(ANDROID_NDK_ROOT)/sysroot/usr/include/arm-linux-androideabi",
 		}
 		buildoptions {
 			"-gcc-toolchain $(ANDROID_NDK_ARM)",
@@ -898,42 +905,14 @@ function toolchain(_buildDir, _libDir)
 			"-Wl,--fix-cortex-a8",
 		}
 
-	configuration { "android-mips" }
-		targetdir (path.join(_buildDir, "android-mips/bin"))
-		objdir (path.join(_buildDir, "android-mips/obj"))
-		libdirs {
-			path.join(_libDir, "lib/android-mips"),
-			"$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/mips",
-		}
-		includedirs {
-			"$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/mips/include",
-		}
-		buildoptions {
-			"-gcc-toolchain $(ANDROID_NDK_MIPS)",
-			"--sysroot=" .. path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-mips"),
-			"-target mipsel-none-linux-android",
-			"-mips32",
-			"-Wunused-value",
-			"-Wundef",
-		}
-		linkoptions {
-			"-gcc-toolchain $(ANDROID_NDK_MIPS)",
-			"--sysroot=" .. path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-mips"),
-			path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-mips/usr/lib/crtbegin_so.o"),
-			path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-mips/usr/lib/crtend_so.o"),
-			"-target mipsel-none-linux-android",
-			"-mips32",
-		}
-
 	configuration { "android-x86" }
 		targetdir (path.join(_buildDir, "android-x86/bin"))
 		objdir (path.join(_buildDir, "android-x86/obj"))
 		libdirs {
-			path.join(_libDir, "lib/android-x86"),
 			"$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/x86",
 		}
 		includedirs {
-			"$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/x86/include",
+			"$(ANDROID_NDK_ROOT)/sysroot/usr/include/x86_64-linux-android",
 		}
 		buildoptions {
 			"-gcc-toolchain $(ANDROID_NDK_X86)",
@@ -966,6 +945,9 @@ function toolchain(_buildDir, _libDir)
 			"-Wunused-value",
 			"-Wundef",
 		}
+		buildoptions_cpp {
+			"-std=c++14",
+		}
 
 	configuration { "freebsd" }
 		targetdir (path.join(_buildDir, "freebsd/bin"))
@@ -1023,6 +1005,12 @@ function toolchain(_buildDir, _libDir)
 		objdir (path.join(_buildDir, "osx_universal/bin"))
 
 	configuration { "osx" }
+		buildoptions_cpp {
+			"-std=c++14",
+		}
+		buildoptions_objcpp {
+			"-std=c++14",
+		}
 		buildoptions {
 			"-Wfatal-errors",
 			"-msse2",
@@ -1035,6 +1023,12 @@ function toolchain(_buildDir, _libDir)
 		linkoptions {
 			"-lc++",
 		}
+		buildoptions_cpp {
+			"-std=c++14",
+		}
+		buildoptions_objcpp {
+			"-std=c++14",
+		}
 		buildoptions {
 			"-Wfatal-errors",
 			"-Wunused-value",
@@ -1042,7 +1036,7 @@ function toolchain(_buildDir, _libDir)
 		}
 		includedirs { path.join(bxDir, "include/compat/ios") }
 
-	configuration { "xcode4", "ios*" }
+	configuration { "xcode*", "ios*" }
 		targetdir (path.join(_buildDir, "ios-arm/bin"))
 		objdir (path.join(_buildDir, "ios-arm/obj"))
 
@@ -1079,6 +1073,7 @@ function toolchain(_buildDir, _libDir)
 		buildoptions {
 			"-miphoneos-version-min=7.0",
 			"--sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS" ..iosPlatform .. ".sdk",
+			"-fembed-bitcode",
 		}
 
 	configuration { "ios-simulator" }
@@ -1128,7 +1123,7 @@ function toolchain(_buildDir, _libDir)
 		}
 		includedirs { path.join(bxDir, "include/compat/ios") }
 
-	configuration { "xcode4", "tvos*" }
+	configuration { "xcode*", "tvos*" }
 		targetdir (path.join(_buildDir, "tvos-arm64/bin"))
 		objdir (path.join(_buildDir, "tvos-arm64/obj"))
 
@@ -1177,6 +1172,9 @@ function toolchain(_buildDir, _libDir)
 			"$(SCE_ORBIS_SDK_DIR)/target/include",
 			"$(SCE_ORBIS_SDK_DIR)/target/include_common",
 		}
+		buildoptions_cpp {
+			"-std=c++14",
+		}
 
 	configuration { "rpi" }
 		targetdir (path.join(_buildDir, "rpi/bin"))
@@ -1193,6 +1191,9 @@ function toolchain(_buildDir, _libDir)
 			"-Wunused-value",
 			"-Wundef",
 		}
+		buildoptions_cpp {
+			"-std=c++14",
+		}
 		includedirs {
 			"/opt/vc/include",
 			"/opt/vc/include/interface/vcos/pthreads",
@@ -1214,13 +1215,16 @@ function toolchain(_buildDir, _libDir)
 			"__MISC_VISIBLE",
 		}
 		includedirs {
-			"$(FREEDOM_E_SDK)/toolchain/riscv32-unknown-elf/include",
+			"$(FREEDOM_E_SDK)/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/riscv64-unknown-elf/include",
 			path.join(bxDir, "include/compat/riscv"),
 		}
 		buildoptions {
 			"-Wunused-value",
 			"-Wundef",
-			"--sysroot=$(FREEDOM_E_SDK)/toolchain/riscv32-unknown-elf",
+			"--sysroot=$(FREEDOM_E_SDK)/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/riscv64-unknown-elf",
+		}
+		buildoptions_cpp {
+			"-std=c++14",
 		}
 
 	configuration {} -- reset configuration
@@ -1236,12 +1240,6 @@ function strip()
 			"$(SILENT) $(ANDROID_NDK_ARM)/bin/arm-linux-androideabi-strip -s \"$(TARGET)\""
 		}
 
-	configuration { "android-mips", "Release" }
-		postbuildcommands {
-			"$(SILENT) echo Stripping symbols.",
-			"$(SILENT) $(ANDROID_NDK_MIPS)/bin/mipsel-linux-android-strip -s \"$(TARGET)\""
-		}
-
 	configuration { "android-x86", "Release" }
 		postbuildcommands {
 			"$(SILENT) echo Stripping symbols.",
@@ -1287,7 +1285,7 @@ function strip()
 	configuration { "riscv" }
 		postbuildcommands {
 			"$(SILENT) echo Stripping symbols.",
-			"$(SILENT) $(FREEDOM_E_SDK)/toolchain/bin/riscv32-unknown-elf-strip -s \"$(TARGET)\""
+			"$(SILENT) $(FREEDOM_E_SDK)/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/bin/riscv64-unknown-elf-strip -s \"$(TARGET)\""
 		}
 
 	configuration {} -- reset configuration

+ 2 - 2
bx.mod/bx/src/bx.cpp

@@ -13,14 +13,14 @@
 
 namespace bx
 {
-	void xchg(void* _a, void* _b, size_t _numBytes)
+	void swap(void* _a, void* _b, size_t _numBytes)
 	{
 		uint8_t* lhs = (uint8_t*)_a;
 		uint8_t* rhs = (uint8_t*)_b;
 		const uint8_t* end = rhs + _numBytes;
 		while (rhs != end)
 		{
-			xchg(*lhs++, *rhs++);
+			swap(*lhs++, *rhs++);
 		}
 	}
 

+ 9 - 7
bx.mod/bx/src/commandline.cpp

@@ -9,12 +9,14 @@
 
 namespace bx
 {
-	// Reference:
-	// http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
-	const char* tokenizeCommandLine(const char* _commandLine, char* _buffer, uint32_t& _bufferSize, int32_t& _argc, char* _argv[], int32_t _maxArgvs, char _term)
+	// Reference(s):
+	// - https://web.archive.org/web/20180629044234/https://msdn.microsoft.com/en-us/library/a1y7w461.aspx
+	//
+	StringView tokenizeCommandLine(const StringView& _commandLine, char* _buffer, uint32_t& _bufferSize, int32_t& _argc, char* _argv[], int32_t _maxArgvs, char _term)
 	{
 		int32_t argc = 0;
-		const char* curr = _commandLine;
+		const char* curr = _commandLine.getPtr();
+		const char* end  = _commandLine.getTerm();
 		char* currOut = _buffer;
 		char term = ' ';
 		bool sub = false;
@@ -30,7 +32,7 @@ namespace bx
 
 		ParserState state = SkipWhitespace;
 
-		while ('\0' != *curr
+		while (end != curr
 		&&     _term != *curr
 		&&     argc < _maxArgvs)
 		{
@@ -64,7 +66,7 @@ namespace bx
 						state = Escape;
 					}
 					else if ('"' == *curr
-						&&  '"' != term)
+					     &&  '"' != term)
 					{
 						sub = !sub;
 					}
@@ -135,7 +137,7 @@ namespace bx
 			++curr;
 		}
 
-		return curr;
+		return StringView(curr, _commandLine.getTerm() );
 	}
 
 	CommandLine::CommandLine(int32_t _argc, char const* const* _argv)

+ 10 - 9
bx.mod/bx/src/crtnone.cpp

@@ -75,7 +75,7 @@ extern "C" char* strcat(char* _dst, const char* _src)
 
 extern "C" const char* strchr(const char* _str, int _ch)
 {
-	return bx::strFind(_str, _ch);
+	return bx::strFind(_str, _ch).getPtr();
 }
 
 extern "C" int32_t strcmp(const char* _lhs, const char* _rhs)
@@ -95,7 +95,7 @@ extern "C" int32_t strcasecmp(const char* _lhs, const char* _rhs)
 
 extern "C" const char* strstr(const char* _str, const char* _find)
 {
-	return bx::strFind(_str, _find);
+	return bx::strFind(_str, _find).getPtr();
 }
 
 extern "C" void qsort(void* _base, size_t _num, size_t _size, bx::ComparisonFn _fn)
@@ -109,7 +109,7 @@ extern "C" int isprint(int _ch)
 	return bx::isPrint(_ch);
 }
 
-extern "C" int toupper (int _ch)
+extern "C" int toupper(int _ch)
 {
 	return bx::toUpper(_ch);
 }
@@ -122,8 +122,10 @@ extern "C" size_t mbstowcs(wchar_t* _dst, const char* _src, size_t _max)
 
 extern "C" char* strdup(const char* _src)
 {
-	uint32_t size = bx::strLen(_src);
-	return (char*)malloc(size);
+	uint32_t size = bx::strLen(_src)+1;
+	char* dup = (char*)malloc(size);
+	bx::strCopy(dup, size, _src);
+	return dup;
 }
 
 extern "C" long int strtol(const char* _str, char** _end, int _base)
@@ -302,7 +304,8 @@ extern "C" int printf(const char* _format, ...)
 	va_list argList;
 	va_start(argList, _format);
 	bx::WriterI* writer = bx::getStdOut();
-	int32_t len = bx::writePrintfVargs(writer, _format, argList);
+	bx::Error err;
+	int32_t len = bx::write(writer, &err, _format, argList);
 	va_end(argList);
 	return len;
 }
@@ -519,9 +522,7 @@ extern "C" char* getcwd(char* _buf, size_t _size)
 
 extern "C" char* getenv(const char* _name)
 {
-	BX_UNUSED(_name);
-	bx::debugPrintf("getenv(%s) not implemented!\n", _name);
-	return NULL;
+	return const_cast<char*>(crt0::getEnv(_name) );
 }
 
 extern "C" int setenv(const char* _name, const char* _value, int _overwrite)

+ 0 - 2
bx.mod/bx/src/debug.cpp

@@ -8,7 +8,6 @@
 #include <bx/string.h>       // isPrint
 #include <bx/readerwriter.h> // WriterI
 #include <inttypes.h>        // PRIx*
-#include <iostream>
 
 #if BX_CRT_NONE
 #	include "crt0.h"
@@ -63,7 +62,6 @@ namespace bx
 	|| BX_PLATFORM_WINRT   \
 	|| BX_PLATFORM_XBOXONE
 		OutputDebugStringA(_out);
-		//std::cout << _out << std::endl;
 #elif  BX_PLATFORM_IOS \
 	|| BX_PLATFORM_OSX
 #	if defined(__OBJC__)

+ 40 - 26
bx.mod/bx/src/dtoa.cpp

@@ -467,12 +467,12 @@ namespace bx
 	{
 		for (int32_t ii = 0, jj = _len - 1; ii < jj; ++ii, --jj)
 		{
-			xchg(_dst[ii], _dst[jj]);
+			swap(_dst[ii], _dst[jj]);
 		}
 	}
 
 	template<typename Ty>
-	int32_t toStringSigned(char* _dst, int32_t _max, Ty _value, uint32_t _base)
+	int32_t toStringSigned(char* _dst, int32_t _max, Ty _value, uint32_t _base, char _separator)
 	{
 		if (_base == 10
 		&&  _value < 0)
@@ -483,10 +483,11 @@ namespace bx
 			}
 
 			_max = toString(_dst + 1
-					, _max - 1
-					, typename std::make_unsigned<Ty>::type(-_value)
-					, _base
-					);
+				, _max - 1
+				, typename std::make_unsigned<Ty>::type(-_value)
+				, _base
+				, _separator
+				);
 			if (_max == 0)
 			{
 				return 0;
@@ -497,24 +498,25 @@ namespace bx
 		}
 
 		return toString(_dst
-					, _max
-					, typename std::make_unsigned<Ty>::type(_value)
-					, _base
-					);
+			, _max
+			, typename std::make_unsigned<Ty>::type(_value)
+			, _base
+			, _separator
+			);
 	}
 
-	int32_t toString(char* _dst, int32_t _max, int32_t _value, uint32_t _base)
+	int32_t toString(char* _dst, int32_t _max, int32_t _value, uint32_t _base, char _separator)
 	{
-		return toStringSigned(_dst, _max, _value, _base);
+		return toStringSigned(_dst, _max, _value, _base, _separator);
 	}
 
-	int32_t toString(char* _dst, int32_t _max, int64_t _value, uint32_t _base)
+	int32_t toString(char* _dst, int32_t _max, int64_t _value, uint32_t _base, char _separator)
 	{
-		return toStringSigned(_dst, _max, _value, _base);
+		return toStringSigned(_dst, _max, _value, _base, _separator);
 	}
 
 	template<typename Ty>
-	int32_t toStringUnsigned(char* _dst, int32_t _max, Ty _value, uint32_t _base)
+	int32_t toStringUnsigned(char* _dst, int32_t _max, Ty _value, uint32_t _base, char _separator)
 	{
 		char data[32];
 		int32_t len = 0;
@@ -525,6 +527,8 @@ namespace bx
 			return 0;
 		}
 
+		uint32_t count = 1;
+
 		do
 		{
 			const Ty rem = _value % _base;
@@ -538,7 +542,16 @@ namespace bx
 				data[len++] = char('a' + rem - 10);
 			}
 
-		} while (_value != 0);
+			if ('\0' != _separator
+			&&  0 == count%3
+			&&  0 != _value)
+			{
+				data[len++] = _separator;
+			}
+
+			++count;
+		}
+		while (0 != _value);
 
 		if (_max < len + 1)
 		{
@@ -552,14 +565,14 @@ namespace bx
 		return int32_t(len);
 	}
 
-	int32_t toString(char* _dst, int32_t _max, uint32_t _value, uint32_t _base)
+	int32_t toString(char* _dst, int32_t _max, uint32_t _value, uint32_t _base, char _separator)
 	{
-		return toStringUnsigned(_dst, _max, _value, _base);
+		return toStringUnsigned(_dst, _max, _value, _base, _separator);
 	}
 
-	int32_t toString(char* _dst, int32_t _max, uint64_t _value, uint32_t _base)
+	int32_t toString(char* _dst, int32_t _max, uint64_t _value, uint32_t _base, char _separator)
 	{
-		return toStringUnsigned(_dst, _max, _value, _base);
+		return toStringUnsigned(_dst, _max, _value, _base, _separator);
 	}
 
 	/*
@@ -1107,11 +1120,12 @@ namespace bx
 
 	bool fromString(int32_t* _out, const StringView& _str)
 	{
-		const char* str  = _str.getPtr();
-		const char* term = _str.getTerm();
+		StringView str = bx::strLTrimSpace(_str);
+
+		const char* ptr  = str.getPtr();
+		const char* term = str.getTerm();
 
-		str = strws(str);
-		char ch = *str++;
+		char ch = *ptr++;
 		bool neg = false;
 		switch (ch)
 		{
@@ -1120,13 +1134,13 @@ namespace bx
 			break;
 
 		default:
-			--str;
+			--ptr;
 			break;
 		}
 
 		int32_t result = 0;
 
-		for (ch = *str++; isNumeric(ch) && str <= term; ch = *str++)
+		for (ch = *ptr++; isNumeric(ch) && ptr <= term; ch = *ptr++)
 		{
 			result = 10*result - (ch - '0');
 		}

+ 2 - 2
bx.mod/bx/src/file.cpp

@@ -51,8 +51,8 @@ namespace bx
 
 		virtual int32_t write(const void* _data, int32_t _size, Error* _err) override
 		{
-			BX_UNUSED(_data, _size, _err);
-			return 0;
+			BX_UNUSED(_data, _err);
+			return _size;
 		}
 	};
 

+ 37 - 33
bx.mod/bx/src/filepath.cpp

@@ -36,8 +36,9 @@ namespace bx
 
 	static int32_t normalizeFilePath(char* _dst, int32_t _dstSize, const char* _src, int32_t _num)
 	{
-		// Reference: Lexical File Names in Plan 9 or Getting Dot-Dot Right
-		// https://9p.io/sys/doc/lexnames.html
+		// Reference(s):
+		// - Lexical File Names in Plan 9 or Getting Dot-Dot Right
+		//   https://web.archive.org/web/20180629044444/https://9p.io/sys/doc/lexnames.html
 
 		const int32_t num = strLen(_src, _num);
 
@@ -153,12 +154,12 @@ namespace bx
 		return size;
 	}
 
-	static bool getEnv(const char* _name, FileInfo::Enum _type, char* _out, uint32_t* _inOutSize)
+	static bool getEnv(char* _out, uint32_t* _inOutSize, const StringView& _name, FileInfo::Enum _type)
 	{
 		uint32_t len = *_inOutSize;
 		*_out = '\0';
 
-		if (getenv(_name, _out, &len) )
+		if (getEnv(_out, &len, _name) )
 		{
 			FileInfo fi;
 			if (stat(_out, fi)
@@ -190,18 +191,22 @@ namespace bx
 	static bool getCurrentPath(char* _out, uint32_t* _inOutSize)
 	{
 		uint32_t len = *_inOutSize;
-		pwd(_out, len);
-		*_inOutSize = strLen(_out);
-		return true;
+		if (NULL != pwd(_out, len))
+		{
+			*_inOutSize = strLen(_out);
+			return true;
+		}
+
+		return false;
 	}
 
 	static bool getHomePath(char* _out, uint32_t* _inOutSize)
 	{
 		return false
 #if BX_PLATFORM_WINDOWS
-			|| getEnv("USERPROFILE", FileInfo::Directory, _out, _inOutSize)
+			|| getEnv(_out, _inOutSize, "USERPROFILE", FileInfo::Directory)
 #endif // BX_PLATFORM_WINDOWS
-			|| getEnv("HOME", FileInfo::Directory, _out, _inOutSize)
+			|| getEnv(_out, _inOutSize, "HOME", FileInfo::Directory)
 			;
 	}
 
@@ -213,21 +218,21 @@ namespace bx
 		*_inOutSize = len;
 		return result;
 #else
-		static const char* s_tmp[] =
+		static const StringView s_tmp[] =
 		{
 			"TMPDIR",
 			"TMP",
 			"TEMP",
 			"TEMPDIR",
 
-			NULL
+			""
 		};
 
-		for (const char** tmp = s_tmp; *tmp != NULL; ++tmp)
+		for (const StringView* tmp = s_tmp; !tmp->isEmpty(); ++tmp)
 		{
 			uint32_t len = *_inOutSize;
 			*_out = '\0';
-			bool ok = getEnv(*tmp, FileInfo::Directory, _out, &len);
+			bool ok = getEnv(_out, &len, *tmp, FileInfo::Directory);
 
 			if (ok
 			&&  len != 0
@@ -336,37 +341,37 @@ namespace bx
 		return m_filePath;
 	}
 
-	const StringView FilePath::getPath() const
+	StringView FilePath::getPath() const
 	{
-		const char* end = strRFind(m_filePath, '/');
-		if (NULL != end)
+		StringView end = strRFind(m_filePath, '/');
+		if (!end.isEmpty() )
 		{
-			return StringView(m_filePath, end+1);
+			return StringView(m_filePath, end.getPtr()+1);
 		}
 
 		return StringView();
 	}
 
-	const StringView FilePath::getFileName() const
+	StringView FilePath::getFileName() const
 	{
-		const char* fileName = strRFind(m_filePath, '/');
-		if (NULL != fileName)
+		StringView fileName = strRFind(m_filePath, '/');
+		if (!fileName.isEmpty() )
 		{
-			return StringView(fileName+1);
+			return StringView(fileName.getPtr()+1);
 		}
 
 		return get();
 	}
 
-	const StringView FilePath::getBaseName() const
+	StringView FilePath::getBaseName() const
 	{
 		const StringView fileName = getFileName();
 		if (!fileName.isEmpty() )
 		{
-			const char* ext = strFind(fileName, '.');
-			if (ext != NULL)
+			StringView ext = strFind(fileName, '.');
+			if (!ext.isEmpty() )
 			{
-				return StringView(fileName.getPtr(), ext);
+				return StringView(fileName.getPtr(), ext.getPtr() );
 			}
 
 			return fileName;
@@ -375,13 +380,12 @@ namespace bx
 		return StringView();
 	}
 
-	const StringView FilePath::getExt() const
+	StringView FilePath::getExt() const
 	{
 		const StringView fileName = getFileName();
 		if (!fileName.isEmpty() )
 		{
-			const char* ext = strFind(fileName, '.');
-			return StringView(ext);
+			return strFind(fileName, '.');
 		}
 
 		return StringView();
@@ -450,13 +454,13 @@ namespace bx
 			return false;
 		}
 
-		const StringView dir = strRTrim(_filePath.get(), "/");
-		const char* slash = strRFind(dir, '/');
+		const StringView dir   = strRTrim(_filePath.get(), "/");
+		const StringView slash = strRFind(dir, '/');
 
-		if (NULL != slash
-		&&  slash - dir.getPtr() > 1)
+		if (!slash.isEmpty()
+		&&  slash.getPtr() - dir.getPtr() > 1)
 		{
-			if (!makeAll(StringView(dir.getPtr(), slash), _err) )
+			if (!makeAll(StringView(dir.getPtr(), slash.getPtr() ), _err) )
 			{
 				return false;
 			}

+ 56 - 104
bx.mod/bx/src/math.cpp

@@ -9,35 +9,21 @@
 
 namespace bx
 {
-	const float kPi         = 3.1415926535897932384626433832795f;
-	const float kPi2        = 6.2831853071795864769252867665590f;
-	const float kInvPi      = 1.0f/kPi;
-	const float kPiHalf     = 1.5707963267948966192313216916398f;
-	const float kPiQuarter  = 0.7853981633974483096156608458199f;
-	const float kSqrt2      = 1.4142135623730950488016887242097f;
-	const float kLogNat10   = 2.3025850929940456840179914546844f;
-	const float kInvLogNat2 = 1.4426950408889634073599246810019f;
-	const float kLogNat2Hi  = 0.6931471805599453094172321214582f;
-	const float kLogNat2Lo  = 1.90821492927058770002e-10f;
-	const float kE          = 2.7182818284590452353602874713527f;
-	const float kNearZero   = 1.0f/float(1 << 28);
-	const float kFloatMin   = 1.175494e-38f;
-	const float kFloatMax   = 3.402823e+38f;
-	const float kInfinity   = bitsToFloat(UINT32_C(0x7f800000) );
+	const float kInfinity = bitsToFloat(UINT32_C(0x7f800000) );
 
 	namespace
 	{
-		static const float kSinC2  = -0.16666667163372039794921875f;
-		static const float kSinC4  =  8.333347737789154052734375e-3f;
-		static const float kSinC6  = -1.9842604524455964565277099609375e-4f;
-		static const float kSinC8  =  2.760012648650445044040679931640625e-6f;
-		static const float kSinC10 = -2.50293279435709337121807038784027099609375e-8f;
+		constexpr float kSinC2  = -0.16666667163372039794921875f;
+		constexpr float kSinC4  =  8.333347737789154052734375e-3f;
+		constexpr float kSinC6  = -1.9842604524455964565277099609375e-4f;
+		constexpr float kSinC8  =  2.760012648650445044040679931640625e-6f;
+		constexpr float kSinC10 = -2.50293279435709337121807038784027099609375e-8f;
 
-		static const float kCosC2  = -0.5f;
-		static const float kCosC4  =  4.166664183139801025390625e-2f;
-		static const float kCosC6  = -1.388833043165504932403564453125e-3f;
-		static const float kCosC8  =  2.47562347794882953166961669921875e-5f;
-		static const float kCosC10 = -2.59630184018533327616751194000244140625e-7f;
+		constexpr float kCosC2  = -0.5f;
+		constexpr float kCosC4  =  4.166664183139801025390625e-2f;
+		constexpr float kCosC6  = -1.388833043165504932403564453125e-3f;
+		constexpr float kCosC8  =  2.47562347794882953166961669921875e-5f;
+		constexpr float kCosC10 = -2.59630184018533327616751194000244140625e-7f;
 
 	} // namespace
 
@@ -86,10 +72,10 @@ namespace bx
 
 	namespace
 	{
-		static const float kAcosC0 =  1.5707288f;
-		static const float kAcosC1 = -0.2121144f;
-		static const float kAcosC2 =  0.0742610f;
-		static const float kAcosC3 = -0.0187293f;
+		constexpr float kAcosC0 =  1.5707288f;
+		constexpr float kAcosC1 = -0.2121144f;
+		constexpr float kAcosC2 =  0.0742610f;
+		constexpr float kAcosC3 = -0.0187293f;
 
 	} // namespace
 
@@ -109,12 +95,12 @@ namespace bx
 
 	namespace
 	{
-		static const float kAtan2C0 = -0.013480470f;
-		static const float kAtan2C1 =  0.057477314f;
-		static const float kAtan2C2 = -0.121239071f;
-		static const float kAtan2C3 =  0.195635925f;
-		static const float kAtan2C4 = -0.332994597f;
-		static const float kAtan2C5 =  0.999995630f;
+		constexpr float kAtan2C0 = -0.013480470f;
+		constexpr float kAtan2C1 =  0.057477314f;
+		constexpr float kAtan2C2 = -0.121239071f;
+		constexpr float kAtan2C3 =  0.195635925f;
+		constexpr float kAtan2C4 = -0.332994597f;
+		constexpr float kAtan2C5 =  0.999995630f;
 
 	} // namespace
 
@@ -175,11 +161,11 @@ namespace bx
 
 	namespace
 	{
-		static const float kExpC0  =  1.66666666666666019037e-01f;
-		static const float kExpC1  = -2.77777777770155933842e-03f;
-		static const float kExpC2  =  6.61375632143793436117e-05f;
-		static const float kExpC3  = -1.65339022054652515390e-06f;
-		static const float kExpC4  =  4.13813679705723846039e-08f;
+		constexpr float kExpC0  =  1.66666666666666019037e-01f;
+		constexpr float kExpC1  = -2.77777777770155933842e-03f;
+		constexpr float kExpC2  =  6.61375632143793436117e-05f;
+		constexpr float kExpC3  = -1.65339022054652515390e-06f;
+		constexpr float kExpC4  =  4.13813679705723846039e-08f;
 
 	} // namespace
 
@@ -209,13 +195,13 @@ namespace bx
 
 	namespace
 	{
-		static const float kLogC0 = 6.666666666666735130e-01f;
-		static const float kLogC1 = 3.999999999940941908e-01f;
-		static const float kLogC2 = 2.857142874366239149e-01f;
-		static const float kLogC3 = 2.222219843214978396e-01f;
-		static const float kLogC4 = 1.818357216161805012e-01f;
-		static const float kLogC5 = 1.531383769920937332e-01f;
-		static const float kLogC6 = 1.479819860511658591e-01f;
+		constexpr float kLogC0 = 6.666666666666735130e-01f;
+		constexpr float kLogC1 = 3.999999999940941908e-01f;
+		constexpr float kLogC2 = 2.857142874366239149e-01f;
+		constexpr float kLogC3 = 2.222219843214978396e-01f;
+		constexpr float kLogC4 = 1.818357216161805012e-01f;
+		constexpr float kLogC5 = 1.531383769920937332e-01f;
+		constexpr float kLogC6 = 1.479819860511658591e-01f;
 
 	} // namespace
 
@@ -253,82 +239,48 @@ namespace bx
 		return result;
 	}
 
-	BX_CONST_FUNC float floor(float _a)
+	static void mtxLookAtImpl(float* _result, const Vec3& _eye, const Vec3& _view, const Vec3& _up)
 	{
-		if (_a < 0.0f)
-		{
-			const float fr = fract(-_a);
-			const float result = -_a - fr;
-
-			return -(0.0f != fr
-				? result + 1.0f
-				: result)
-				;
-		}
-
-		return _a - fract(_a);
-	}
-
-	void mtxLookAtImpl(float* _result, const float* _eye, const float* _view, const float* _up)
-	{
-		float up[3] = { 0.0f, 1.0f, 0.0f };
-		if (NULL != _up)
-		{
-			up[0] = _up[0];
-			up[1] = _up[1];
-			up[2] = _up[2];
-		}
-
-		float tmp[4];
-		vec3Cross(tmp, up, _view);
-
-		float right[4];
-		vec3Norm(right, tmp);
-
-		vec3Cross(up, _view, right);
+		const Vec3 uxv   = cross(_up, _view);
+		const Vec3 right = normalize(uxv);
+		const Vec3 up    = cross(_view, right);
 
 		memSet(_result, 0, sizeof(float)*16);
-		_result[ 0] = right[0];
-		_result[ 1] = up[0];
-		_result[ 2] = _view[0];
+		_result[ 0] = right.x;
+		_result[ 1] = up.x;
+		_result[ 2] = _view.x;
 
-		_result[ 4] = right[1];
-		_result[ 5] = up[1];
-		_result[ 6] = _view[1];
+		_result[ 4] = right.y;
+		_result[ 5] = up.y;
+		_result[ 6] = _view.y;
 
-		_result[ 8] = right[2];
-		_result[ 9] = up[2];
-		_result[10] = _view[2];
+		_result[ 8] = right.z;
+		_result[ 9] = up.z;
+		_result[10] = _view.z;
 
-		_result[12] = -vec3Dot(right, _eye);
-		_result[13] = -vec3Dot(up, _eye);
-		_result[14] = -vec3Dot(_view, _eye);
+		_result[12] = -dot(right, _eye);
+		_result[13] = -dot(up, _eye);
+		_result[14] = -dot(_view, _eye);
 		_result[15] = 1.0f;
 	}
 
-	void mtxLookAtLh(float* _result, const float* _eye, const float* _at, const float* _up)
+	void mtxLookAtLh(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up)
 	{
-		float tmp[4];
-		vec3Sub(tmp, _at, _eye);
-
-		float view[4];
-		vec3Norm(view, tmp);
+		const Vec3 tmp  = sub(_at, _eye);
+		const Vec3 view = normalize(tmp);
 
 		mtxLookAtImpl(_result, _eye, view, _up);
 	}
 
-	void mtxLookAtRh(float* _result, const float* _eye, const float* _at, const float* _up)
+	void mtxLookAtRh(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up)
 	{
-		float tmp[4];
-		vec3Sub(tmp, _eye, _at);
-
-		float view[4];
-		vec3Norm(view, tmp);
+		const Vec3 tmp = sub(_eye, _at);
+		const Vec3 view = normalize(tmp);
 
 		mtxLookAtImpl(_result, _eye, view, _up);
 	}
 
-	void mtxLookAt(float* _result, const float* _eye, const float* _at, const float* _up)
+	void mtxLookAt(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up)
 	{
 		mtxLookAtLh(_result, _eye, _at, _up);
 	}

+ 49 - 37
bx.mod/bx/src/os.cpp

@@ -8,10 +8,6 @@
 #include <bx/os.h>
 #include <bx/uint32_t.h>
 
-#if !BX_PLATFORM_NONE
-
-#include <stdio.h>
-
 #if BX_CRT_MSVC
 #	include <direct.h>
 #else
@@ -51,11 +47,13 @@
 #	elif   BX_PLATFORM_LINUX     \
 		|| BX_PLATFORM_RPI       \
 		|| BX_PLATFORM_STEAMLINK
+#		include <stdio.h>  // fopen
 #		include <unistd.h> // syscall
 #		include <sys/syscall.h>
 #	elif BX_PLATFORM_OSX
 #		include <mach/mach.h> // mach_task_basic_info
 #	elif BX_PLATFORM_HURD
+#		include <stdio.h>           // fopen
 #		include <pthread/pthread.h> // pthread_self
 #	elif BX_PLATFORM_ANDROID
 #		include "debug.h" // getTid is not implemented...
@@ -173,18 +171,19 @@ namespace bx
 #endif // BX_PLATFORM_*
 	}
 
-	void* dlopen(const char* _filePath)
+	void* dlopen(const FilePath& _filePath)
 	{
 #if BX_PLATFORM_WINDOWS
-		return (void*)::LoadLibraryA(_filePath);
+		return (void*)::LoadLibraryA(_filePath.get() );
 #elif  BX_PLATFORM_EMSCRIPTEN \
 	|| BX_PLATFORM_PS4        \
 	|| BX_PLATFORM_XBOXONE    \
-	|| BX_PLATFORM_WINRT
+	|| BX_PLATFORM_WINRT      \
+	|| BX_CRT_NONE
 		BX_UNUSED(_filePath);
 		return NULL;
 #else
-		return ::dlopen(_filePath, RTLD_LOCAL|RTLD_LAZY);
+		return ::dlopen(_filePath.get(), RTLD_LOCAL|RTLD_LAZY);
 #endif // BX_PLATFORM_
 	}
 
@@ -195,32 +194,42 @@ namespace bx
 #elif  BX_PLATFORM_EMSCRIPTEN \
 	|| BX_PLATFORM_PS4        \
 	|| BX_PLATFORM_XBOXONE    \
-	|| BX_PLATFORM_WINRT
+	|| BX_PLATFORM_WINRT      \
+	|| BX_CRT_NONE
 		BX_UNUSED(_handle);
 #else
 		::dlclose(_handle);
 #endif // BX_PLATFORM_
 	}
 
-	void* dlsym(void* _handle, const char* _symbol)
+	void* dlsym(void* _handle, const StringView& _symbol)
 	{
+		const int32_t symbolMax = _symbol.getLength()+1;
+		char* symbol = (char*)alloca(symbolMax);
+		bx::strCopy(symbol, symbolMax, _symbol);
+
 #if BX_PLATFORM_WINDOWS
-		return (void*)::GetProcAddress( (HMODULE)_handle, _symbol);
+		return (void*)::GetProcAddress( (HMODULE)_handle, symbol);
 #elif  BX_PLATFORM_EMSCRIPTEN \
 	|| BX_PLATFORM_PS4        \
 	|| BX_PLATFORM_XBOXONE    \
-	|| BX_PLATFORM_WINRT
-		BX_UNUSED(_handle, _symbol);
+	|| BX_PLATFORM_WINRT      \
+	|| BX_CRT_NONE
+		BX_UNUSED(_handle, symbol);
 		return NULL;
 #else
-		return ::dlsym(_handle, _symbol);
+		return ::dlsym(_handle, symbol);
 #endif // BX_PLATFORM_
 	}
 
-	bool getenv(const char* _name, char* _out, uint32_t* _inOutSize)
+	bool getEnv(char* _out, uint32_t* _inOutSize, const StringView& _name)
 	{
+		const int32_t nameMax = _name.getLength()+1;
+		char* name = (char*)alloca(nameMax);
+		bx::strCopy(name, nameMax, _name);
+
 #if BX_PLATFORM_WINDOWS
-		DWORD len = ::GetEnvironmentVariableA(_name, _out, *_inOutSize);
+		DWORD len = ::GetEnvironmentVariableA(name, _out, *_inOutSize);
 		bool result = len != 0 && len < *_inOutSize;
 		*_inOutSize = len;
 		return result;
@@ -228,10 +237,10 @@ namespace bx
 	|| BX_PLATFORM_XBOXONE \
 	|| BX_PLATFORM_WINRT   \
 	|| BX_CRT_NONE
-		BX_UNUSED(_name, _out, _inOutSize);
+		BX_UNUSED(name, _out, _inOutSize);
 		return false;
 #else
-		const char* ptr = ::getenv(_name);
+		const char* ptr = ::getenv(name);
 		uint32_t len = 0;
 		bool result = false;
 		if (NULL != ptr)
@@ -250,31 +259,36 @@ namespace bx
 #endif // BX_PLATFORM_
 	}
 
-	void setenv(const char* _name, const char* _value)
+	void setEnv(const StringView& _name, const StringView& _value)
 	{
-#if BX_PLATFORM_WINDOWS
-		::SetEnvironmentVariableA(_name, _value);
-#elif  BX_PLATFORM_PS4     \
-	|| BX_PLATFORM_XBOXONE \
-	|| BX_PLATFORM_WINRT   \
-	|| BX_CRT_NONE
-		BX_UNUSED(_name, _value);
-#else
-		::setenv(_name, _value, 1);
-#endif // BX_PLATFORM_
-	}
+		const int32_t nameMax = _name.getLength()+1;
+		char* name = (char*)alloca(nameMax);
+		bx::strCopy(name, nameMax, _name);
+
+		char* value = NULL;
+		if (!_value.isEmpty() )
+		{
+			int32_t valueMax = _value.getLength()+1;
+			value = (char*)alloca(valueMax);
+			bx::strCopy(value, valueMax, _value);
+		}
 
-	void unsetenv(const char* _name)
-	{
 #if BX_PLATFORM_WINDOWS
-		::SetEnvironmentVariableA(_name, NULL);
+		::SetEnvironmentVariableA(name, value);
 #elif  BX_PLATFORM_PS4     \
 	|| BX_PLATFORM_XBOXONE \
 	|| BX_PLATFORM_WINRT   \
 	|| BX_CRT_NONE
-		BX_UNUSED(_name);
+		BX_UNUSED(name, value);
 #else
-		::unsetenv(_name);
+		if (NULL != value)
+		{
+			::setenv(name, value, 1);
+		}
+		else
+		{
+			::unsetenv(name);
+		}
 #endif // BX_PLATFORM_
 	}
 
@@ -355,5 +369,3 @@ namespace bx
 	}
 
 } // namespace bx
-
-#endif // !BX_PLATFORM_NONE

+ 3 - 4
bx.mod/bx/src/settings.cpp

@@ -59,12 +59,11 @@ void Settings::load(const void* _data, uint32_t _len)
 	}
 	else
 	{
-		BX_UNUSED(_len);
-		m_ini = ini_load( (const char*)_data, m_allocator);
+		m_ini = ini_load( (const char*)_data, _len, m_allocator);
 	}
 }
 
-const char* Settings::get(const StringView& _name) const
+StringView Settings::get(const StringView& _name) const
 {
 	ini_t* ini = INI_T(m_ini);
 
@@ -85,7 +84,7 @@ const char* Settings::get(const StringView& _name) const
 	int32_t property = ini_find_property(ini, section, fileName.getPtr(), fileName.getLength() );
 	if (INI_NOT_FOUND == property)
 	{
-		return NULL;
+		return StringView();
 	}
 
 	return ini_property_value(ini, section, property);

+ 2 - 2
bx.mod/bx/src/sort.cpp

@@ -27,12 +27,12 @@ namespace bx
 			int32_t result = _fn(&data[ii*_stride], _pivot);
 			if (0 > result)
 			{
-				xchg(&data[ll*_stride], &data[ii*_stride], _stride);
+				swap(&data[ll*_stride], &data[ii*_stride], _stride);
 				++ll;
 			}
 			else if (0 == result)
 			{
-				xchg(&data[gg*_stride], &data[ii*_stride], _stride);
+				swap(&data[gg*_stride], &data[ii*_stride], _stride);
 				++gg;
 				++ii;
 			}

+ 178 - 128
bx.mod/bx/src/string.cpp

@@ -9,10 +9,6 @@
 #include <bx/readerwriter.h>
 #include <bx/string.h>
 
-#if !BX_CRT_NONE
-#	include <stdio.h> // vsnprintf
-#endif // !BX_CRT_NONE
-
 namespace bx
 {
 	inline bool isInRange(char _ch, char _from, char _to)
@@ -361,9 +357,15 @@ namespace bx
 		return strFindUnsafe(_str, strLen(_str, _max), _ch);
 	}
 
-	const char* strFind(const StringView& _str, char _ch)
+	StringView strFind(const StringView& _str, char _ch)
 	{
-		return strFind(_str.getPtr(), _str.getLength(), _ch);
+		const char* ptr = strFindUnsafe(_str.getPtr(), _str.getLength(), _ch);
+		if (NULL == ptr)
+		{
+			return StringView(_str.getTerm(), _str.getTerm() );
+		}
+
+		return StringView(ptr, ptr+1);
 	}
 
 	inline const char* strRFindUnsafe(const char* _str, int32_t _len, char _ch)
@@ -379,14 +381,15 @@ namespace bx
 		return NULL;
 	}
 
-	inline const char* strRFind(const char* _str, int32_t _max, char _ch)
+	StringView strRFind(const StringView& _str, char _ch)
 	{
-		return strRFindUnsafe(_str, strLen(_str, _max), _ch);
-	}
+		const char* ptr = strRFindUnsafe(_str.getPtr(), _str.getLength(), _ch);
+		if (NULL == ptr)
+		{
+			return StringView(_str.getTerm(), _str.getTerm() );
+		}
 
-	const char* strRFind(const StringView& _str, char _ch)
-	{
-		return strRFind(_str.getPtr(), _str.getLength(), _ch);
+		return StringView(ptr, ptr+1);
 	}
 
 	template<CharFn fn>
@@ -394,8 +397,8 @@ namespace bx
 	{
 		const char* ptr = _str;
 
-		int32_t       stringLen = strLen(_str,  _strMax);
-		const int32_t findLen   = strLen(_find, _findMax);
+		int32_t       stringLen = _strMax;
+		const int32_t findLen   = _findMax;
 
 		for (; stringLen >= findLen; ++ptr, --stringLen)
 		{
@@ -430,24 +433,42 @@ namespace bx
 		return NULL;
 	}
 
-	const char* strFind(const StringView& _str, const StringView& _find, int32_t _num)
+	StringView strFind(const StringView& _str, const StringView& _find, int32_t _num)
 	{
-		return strFind<toNoop>(
+		int32_t len = min(_find.getLength(), _num);
+
+		const char* ptr = strFind<toNoop>(
 			  _str.getPtr()
 			, _str.getLength()
 			, _find.getPtr()
-			, min(_find.getLength(), _num)
+			, len
 			);
+
+		if (NULL == ptr)
+		{
+			return StringView(_str.getTerm(), _str.getTerm() );
+		}
+
+		return StringView(ptr, len);
 	}
 
-	const char* strFindI(const StringView& _str, const StringView& _find, int32_t _num)
+	StringView strFindI(const StringView& _str, const StringView& _find, int32_t _num)
 	{
-		return strFind<toLower>(
+		int32_t len = min(_find.getLength(), _num);
+
+		const char* ptr = strFind<toLower>(
 			  _str.getPtr()
 			, _str.getLength()
 			, _find.getPtr()
-			, min(_find.getLength(), _num)
+			, len
 			);
+
+		if (NULL == ptr)
+		{
+			return StringView(_str.getTerm(), _str.getTerm() );
+		}
+
+		return StringView(ptr, len);
 	}
 
 	StringView strLTrim(const StringView& _str, const StringView& _chars)
@@ -464,29 +485,53 @@ namespace bx
 			}
 		}
 
-		return StringView();
+		return _str;
 	}
 
-	StringView strRTrim(const StringView& _str, const StringView& _chars)
+	StringView strLTrimSpace(const StringView& _str)
 	{
-		if (_str.isEmpty() )
+		for (const char* ptr = _str.getPtr(), *term = _str.getTerm(); ptr != term; ++ptr)
 		{
-			return StringView();
+			if (!isSpace(*ptr) )
+			{
+				return StringView(ptr, term);
+			}
 		}
 
-		const char* ptr   = _str.getPtr();
-		const char* chars = _chars.getPtr();
-		const uint32_t charsLen = _chars.getLength();
+		return StringView(_str.getTerm(), _str.getTerm() );
+	}
 
-		for (int32_t len = _str.getLength(), ii = len-1; 0 <= ii; --ii)
+	StringView strLTrimNonSpace(const StringView& _str)
+	{
+		for (const char* ptr = _str.getPtr(), *term = _str.getTerm(); ptr != term; ++ptr)
 		{
-			if (NULL == strFindUnsafe(chars, charsLen, ptr[ii]) )
+			if (isSpace(*ptr) )
+			{
+				return StringView(ptr, term);
+			}
+		}
+
+		return StringView(_str.getTerm(), _str.getTerm() );
+	}
+
+	StringView strRTrim(const StringView& _str, const StringView& _chars)
+	{
+		if (!_str.isEmpty() )
+		{
+			const char* ptr = _str.getPtr();
+			const char* chars = _chars.getPtr();
+			const uint32_t charsLen = _chars.getLength();
+
+			for (int32_t len = _str.getLength(), ii = len - 1; 0 <= ii; --ii)
 			{
-				return StringView(ptr, ii+1);
+				if (NULL == strFindUnsafe(chars, charsLen, ptr[ii]))
+				{
+					return StringView(ptr, ii + 1);
+				}
 			}
 		}
 
-		return StringView();
+		return _str;
 	}
 
 	StringView strTrim(const StringView& _str, const StringView& _chars)
@@ -494,59 +539,57 @@ namespace bx
 		return strLTrim(strRTrim(_str, _chars), _chars);
 	}
 
-	const char* strnl(const char* _str)
+	constexpr uint32_t kFindStep = 1024;
+
+	StringView strFindNl(const StringView& _str)
 	{
-		for (; '\0' != *_str; _str += strLen(_str, 1024) )
+		StringView str(_str);
+
+		for (; str.getPtr() != _str.getTerm()
+			; str = StringView(min(str.getPtr() + kFindStep, _str.getTerm() ), min(str.getPtr() + kFindStep*2, _str.getTerm() ) )
+			)
 		{
-			const char* eol = strFind(StringView(_str, 1024), "\r\n");
-			if (NULL != eol)
+			StringView eol = strFind(str, "\r\n");
+			if (!eol.isEmpty() )
 			{
-				return eol + 2;
+				return StringView(eol.getTerm(), _str.getTerm() );
 			}
 
-			eol = strFind(StringView(_str, 1024), "\n");
-			if (NULL != eol)
+			eol = strFind(str, '\n');
+			if (!eol.isEmpty() )
 			{
-				return eol + 1;
+				return StringView(eol.getTerm(), _str.getTerm() );
 			}
 		}
 
-		return _str;
+		return StringView(_str.getTerm(), _str.getTerm() );
 	}
 
-	const char* streol(const char* _str)
+	StringView strFindEol(const StringView& _str)
 	{
-		for (; '\0' != *_str; _str += strLen(_str, 1024) )
+		StringView str(_str);
+
+		for (; str.getPtr() != _str.getTerm()
+			 ; str = StringView(min(str.getPtr() + kFindStep, _str.getTerm() ), min(str.getPtr() + kFindStep*2, _str.getTerm() ) )
+			)
 		{
-			const char* eol = strFind(StringView(_str, 1024), "\r\n");
-			if (NULL != eol)
+			StringView eol = strFind(str, "\r\n");
+			if (!eol.isEmpty() )
 			{
-				return eol;
+				return StringView(eol.getPtr(), _str.getTerm() );
 			}
 
-			eol = strFind(StringView(_str, 1024), "\n");
-			if (NULL != eol)
+			eol = strFind(str, '\n');
+			if (!eol.isEmpty() )
 			{
-				return eol;
+				return StringView(eol.getPtr(), _str.getTerm() );
 			}
 		}
 
-		return _str;
-	}
-
-	const char* strws(const char* _str)
-	{
-		for (; isSpace(*_str); ++_str) {};
-		return _str;
-	}
-
-	const char* strnws(const char* _str)
-	{
-		for (; !isSpace(*_str); ++_str) {};
-		return _str;
+		return StringView(_str.getTerm(), _str.getTerm() );
 	}
 
-	const char* strSkipWord(const char* _str, int32_t _max)
+	static const char* strSkipWord(const char* _str, int32_t _max)
 	{
 		for (char ch = *_str++; 0 < _max && (isAlphaNum(ch) || '_' == ch); ch = *_str++, --_max) {};
 		return _str-1;
@@ -559,34 +602,54 @@ namespace bx
 		return StringView(ptr, term);
 	}
 
-	const char* strmb(const char* _str, char _open, char _close)
+	StringView strFindBlock(const StringView& _str, char _open, char _close)
 	{
-		int count = 0;
-		for (char ch = *_str++; ch != '\0' && count >= 0; ch = *_str++)
+		const char* curr  = _str.getPtr();
+		const char* term  = _str.getTerm();
+		const char* start = NULL;
+
+		int32_t count = 0;
+		for (char ch = *curr; curr != term && count >= 0; ch = *(++curr) )
 		{
 			if (ch == _open)
 			{
-				count++;
+				if (0 == count)
+				{
+					start = curr;
+				}
+
+				++count;
 			}
 			else if (ch == _close)
 			{
-				count--;
+				--count;
+
+				if (NULL == start)
+				{
+					break;
+				}
+
 				if (0 == count)
 				{
-					return _str-1;
+					return StringView(start, curr+1);
 				}
 			}
 		}
 
-		return NULL;
+		return StringView(term, term);
 	}
 
-	void eolLF(char* _out, int32_t _size, const char* _str)
+	StringView normalizeEolLf(char* _out, int32_t _size, const StringView& _str)
 	{
+		const char* start = _out;
+		const char* end   = _out;
+
 		if (0 < _size)
 		{
-			char* end = _out + _size - 1;
-			for (char ch = *_str++; ch != '\0' && _out < end; ch = *_str++)
+			const char* curr = _str.getPtr();
+			const char* term = _str.getTerm();
+			end  = _out + _size;
+			for (char ch = *curr; curr != term && _out < end; ch = *(++curr) )
 			{
 				if ('\r' != ch)
 				{
@@ -594,26 +657,25 @@ namespace bx
 				}
 			}
 
-			*_out = '\0';
+			end = _out;
 		}
+
+		return StringView(start, end);
 	}
 
-	const char* findIdentifierMatch(const char* _str, const char* _word)
+	StringView findIdentifierMatch(const StringView& _str, const StringView& _word)
 	{
-		int32_t len = strLen(_word);
-		const char* ptr = strFind(_str, _word);
-		for (; NULL != ptr; ptr = strFind(ptr + len, _word) )
+		const int32_t len = _word.getLength();
+		StringView ptr = strFind(_str, _word);
+		for (; !ptr.isEmpty(); ptr = strFind(StringView(ptr.getPtr() + len, _str.getTerm() ), _word) )
 		{
-			if (ptr != _str)
+			char ch = *(ptr.getPtr() - 1);
+			if (isAlphaNum(ch) || '_' == ch)
 			{
-				char ch = *(ptr - 1);
-				if (isAlphaNum(ch) || '_' == ch)
-				{
-					continue;
-				}
+				continue;
 			}
 
-			char ch = ptr[len];
+			ch = *(ptr.getPtr() + len);
 			if (isAlphaNum(ch) || '_' == ch)
 			{
 				continue;
@@ -622,21 +684,21 @@ namespace bx
 			return ptr;
 		}
 
-		return ptr;
+		return StringView(_str.getTerm(), _str.getTerm() );
 	}
 
-	const char* findIdentifierMatch(const char* _str, const char* _words[])
+	StringView findIdentifierMatch(const StringView& _str, const char** _words)
 	{
-		for (const char* word = *_words; NULL != word; ++_words, word = *_words)
+		for (StringView word = *_words; !word.isEmpty(); ++_words, word = *_words)
 		{
-			const char* match = findIdentifierMatch(_str, word);
-			if (NULL != match)
+			StringView match = findIdentifierMatch(_str, word);
+			if (!match.isEmpty() )
 			{
 				return match;
 			}
 		}
 
-		return NULL;
+		return StringView(_str.getTerm(), _str.getTerm() );
 	}
 
 	namespace
@@ -646,7 +708,7 @@ namespace bx
 			Param()
 				: width(0)
 				, base(10)
-				, prec(6)
+				, prec(INT32_MAX)
 				, fill(' ')
 				, bits(0)
 				, left(false)
@@ -657,8 +719,8 @@ namespace bx
 			}
 
 			int32_t width;
-			uint32_t base;
-			uint32_t prec;
+			int32_t base;
+			int32_t prec;
 			char fill;
 			uint8_t bits;
 			bool left;
@@ -716,7 +778,7 @@ namespace bx
 
 		static int32_t write(WriterI* _writer, const char* _str, const Param& _param, Error* _err)
 		{
-			return write(_writer, _str, INT32_MAX, _param, _err);
+			return write(_writer, _str, _param.prec, _param, _err);
 		}
 
 		static int32_t write(WriterI* _writer, int32_t _i, const Param& _param, Error* _err)
@@ -789,10 +851,11 @@ namespace bx
 			const char* dot = strFind(str, INT32_MAX, '.');
 			if (NULL != dot)
 			{
+				const int32_t prec = INT32_MAX == _param.prec ? 6 : _param.prec;
 				const int32_t precLen = int32_t(
 						dot
-						+ uint32_min(_param.prec + _param.spec, 1)
-						+ _param.prec
+						+ uint32_min(prec + _param.spec, 1)
+						+ prec
 						- str
 						);
 				if (precLen > len)
@@ -824,9 +887,9 @@ namespace bx
 		}
 	} // anonymous namespace
 
-	int32_t write(WriterI* _writer, const char* _format, va_list _argList, Error* _err)
+	int32_t write(WriterI* _writer, const StringView& _format, va_list _argList, Error* _err)
 	{
-		MemoryReader reader(_format, uint32_t(strLen(_format) ) );
+		MemoryReader reader(_format.getPtr(), _format.getLength() );
 
 		int32_t size = 0;
 
@@ -1036,11 +1099,18 @@ namespace bx
 			}
 		}
 
-		size += write(_writer, '\0', _err);
-
 		return size;
 	}
 
+	int32_t write(WriterI* _writer, Error* _err, const StringView* _format, ...)
+	{
+		va_list argList;
+		va_start(argList, _format);
+		int32_t total = write(_writer, *_format, argList, _err);
+		va_end(argList);
+		return total;
+	}
+
 	int32_t write(WriterI* _writer, Error* _err, const char* _format, ...)
 	{
 		va_list argList;
@@ -1050,12 +1120,11 @@ namespace bx
 		return total;
 	}
 
-	int32_t vsnprintfRef(char* _out, int32_t _max, const char* _format, va_list _argList)
+	int32_t vsnprintf(char* _out, int32_t _max, const char* _format, va_list _argList)
 	{
 		if (1 < _max)
 		{
-			StaticMemoryBlockWriter writer(_out, uint32_t(_max-1) );
-			_out[_max-1] = '\0';
+			StaticMemoryBlockWriter writer(_out, uint32_t(_max) );
 
 			Error err;
 			va_list argListCopy;
@@ -1065,8 +1134,13 @@ namespace bx
 
 			if (err.isOk() )
 			{
+				size += write(&writer, '\0', &err);
 				return size - 1 /* size without '\0' terminator */;
 			}
+			else
+			{
+				_out[_max-1] = '\0';
+			}
 		}
 
 		Error err;
@@ -1076,31 +1150,7 @@ namespace bx
 		int32_t size = write(&sizer, _format, argListCopy, &err);
 		va_end(argListCopy);
 
-		return size - 1 /* size without '\0' terminator */;
-	}
-
-	int32_t vsnprintf(char* _out, int32_t _max, const char* _format, va_list _argList)
-	{
-		va_list argList;
-		va_copy(argList, _argList);
-		int32_t total = 0;
-#if BX_CRT_NONE
-		total = vsnprintfRef(_out, _max, _format, argList);
-#elif BX_CRT_MSVC
-		int32_t len = -1;
-		if (NULL != _out)
-		{
-			va_list argListCopy;
-			va_copy(argListCopy, _argList);
-			len = ::vsnprintf_s(_out, _max, size_t(-1), _format, argListCopy);
-			va_end(argListCopy);
-		}
-		total = -1 == len ? ::_vscprintf(_format, argList) : len;
-#else
-		total = ::vsnprintf(_out, _max, _format, argList);
-#endif // BX_COMPILER_MSVC
-		va_end(argList);
-		return total;
+		return size;
 	}
 
 	int32_t snprintf(char* _out, int32_t _max, const char* _format, ...)

+ 0 - 2
bx.mod/bx/src/timer.cpp

@@ -28,8 +28,6 @@ namespace bx
 	|| BX_PLATFORM_XBOXONE \
 	|| BX_PLATFORM_WINRT
 		LARGE_INTEGER li;
-		// Performance counter value may unexpectedly leap forward
-		// http://support.microsoft.com/kb/274323
 		QueryPerformanceCounter(&li);
 		int64_t i64 = li.QuadPart;
 #elif BX_PLATFORM_ANDROID

+ 35 - 35
bx.mod/bx/src/url.cpp

@@ -24,22 +24,21 @@ namespace bx
 	{
 		clear();
 
-		const char* start = _url.getPtr();
 		const char* term  = _url.getTerm();
-		const char* schemeEnd = strFind(StringView(start, term), "://");
-		const char* hostStart = NULL != schemeEnd ? schemeEnd+3 : start;
-		const char* pathStart = strFind(StringView(hostStart, term), '/');
+		StringView schemeEnd = strFind(_url, "://");
+		const char* hostStart = !schemeEnd.isEmpty() ? schemeEnd.getTerm() : _url.getPtr();
+		StringView path = strFind(StringView(hostStart, term), '/');
 
-		if (NULL == schemeEnd
-		&&  NULL == pathStart)
+		if (schemeEnd.isEmpty()
+		&&  path.isEmpty() )
 		{
 			return false;
 		}
 
-		if (NULL != schemeEnd
-		&& (NULL == pathStart || pathStart > schemeEnd) )
+		if (!schemeEnd.isEmpty()
+		&& (path.isEmpty() || path.getPtr() > schemeEnd.getPtr() ) )
 		{
-			StringView scheme(start, schemeEnd);
+			const StringView scheme(_url.getPtr(), schemeEnd.getPtr() );
 
 			if (!isAlpha(scheme) )
 			{
@@ -49,63 +48,64 @@ namespace bx
 			m_tokens[Scheme].set(scheme);
 		}
 
-		if (NULL != pathStart)
+		if (!path.isEmpty() )
 		{
-			const char* queryStart    = strFind(StringView(pathStart, term), '?');
-			const char* fragmentStart = strFind(StringView(pathStart, term), '#');
+			path.set(path.getPtr(), term);
+			const StringView query    = strFind(path, '?');
+			const StringView fragment = strFind(path, '#');
 
-			if (NULL != fragmentStart
-			&&  fragmentStart < queryStart)
+			if (!fragment.isEmpty()
+			&&   fragment.getPtr() < query.getPtr() )
 			{
 				return false;
 			}
 
-			m_tokens[Path].set(pathStart
-				, NULL != queryStart    ? queryStart
-				: NULL != fragmentStart ? fragmentStart
+			m_tokens[Path].set(path.getPtr()
+				, !query.isEmpty()    ? query.getPtr()
+				: !fragment.isEmpty() ? fragment.getPtr()
 				: term
 				);
 
-			if (NULL != queryStart)
+			if (!query.isEmpty() )
 			{
-				m_tokens[Query].set(queryStart+1
-					, NULL != fragmentStart ? fragmentStart
+				m_tokens[Query].set(query.getPtr()+1
+					, !fragment.isEmpty() ? fragment.getPtr()
 					: term
 					);
 			}
 
-			if (NULL != fragmentStart)
+			if (!fragment.isEmpty() )
 			{
-				m_tokens[Fragment].set(fragmentStart+1, term);
+				m_tokens[Fragment].set(fragment.getPtr()+1, term);
 			}
 
-			term = pathStart;
+			term = path.getPtr();
 		}
 
-		const char* userPassEnd   = strFind(StringView(hostStart, term), '@');
-		const char* userPassStart = NULL != userPassEnd ? hostStart : NULL;
-		hostStart = NULL != userPassEnd ? userPassEnd+1 : hostStart;
-		const char* portStart = strFind(StringView(hostStart, term), ':');
+		const StringView userPassEnd = strFind(StringView(hostStart, term), '@');
+		const char* userPassStart = !userPassEnd.isEmpty() ? hostStart : NULL;
+		hostStart = !userPassEnd.isEmpty() ? userPassEnd.getPtr()+1 : hostStart;
+		const StringView portStart = strFind(StringView(hostStart, term), ':');
 
-		m_tokens[Host].set(hostStart, NULL != portStart ? portStart : term);
+		m_tokens[Host].set(hostStart, !portStart.isEmpty() ? portStart.getPtr() : term);
 
-		if (NULL != portStart)
+		if (!portStart.isEmpty())
 		{
-			m_tokens[Port].set(portStart+1, term);
+			m_tokens[Port].set(portStart.getPtr()+1, term);
 		}
 
 		if (NULL != userPassStart)
 		{
-			const char* passStart = strFind(StringView(userPassStart, userPassEnd), ':');
+			StringView passStart = strFind(StringView(userPassStart, userPassEnd.getPtr() ), ':');
 
 			m_tokens[UserName].set(userPassStart
-				, NULL != passStart ? passStart
-				: userPassEnd
+				, !passStart.isEmpty() ? passStart.getPtr()
+				: userPassEnd.getPtr()
 				);
 
-			if (NULL != passStart)
+			if (!passStart.isEmpty() )
 			{
-				m_tokens[Password].set(passStart+1, userPassEnd);
+				m_tokens[Password].set(passStart.getPtr()+1, userPassEnd.getPtr() );
 			}
 		}
 

+ 7 - 6
bx.mod/bx/tests/easing_test.cpp

@@ -11,24 +11,25 @@
 TEST_CASE("easing", "")
 {
 	bx::WriterI* writer = bx::getNullOut();
+	bx::Error err;
 
 	for (uint32_t ee = 0; ee < bx::Easing::Count; ++ee)
 	{
-		bx::writePrintf(writer, "\n\n%d\n", ee);
+		bx::write(writer, &err, "\n\n%d\n", ee);
 
 		const bx::EaseFn easing = bx::getEaseFunc(bx::Easing::Enum(ee) );
 
 		const int32_t nx = 64;
 		const int32_t ny = 10;
 
-		bx::writePrintf(writer, "\t///      ^\n");
+		bx::write(writer, &err, "\t///      ^\n");
 
 		for (int32_t yy = ny+4; yy >= -5; --yy)
 		{
 			const float ys = float(yy    )/float(ny);
 			const float ye = float(yy+1.0)/float(ny);
 
-			bx::writePrintf(writer, "\t///      %c", yy != 0 ? '|' : '+');
+			bx::write(writer, &err, "\t///      %c", yy != 0 ? '|' : '+');
 
 			for (int32_t xx = 0; xx < nx; ++xx)
 			{
@@ -41,18 +42,18 @@ TEST_CASE("easing", "")
 					if (vv >= ys
 					&&  vv <  ye)
 					{
-						bx::writePrintf(writer, "*");
+						bx::write(writer, "*");
 						break;
 					}
 				}
 
 				if (jj == 10)
 				{
-					bx::writePrintf(writer, "%c", yy != 0 ? ' ' : '-');
+					bx::write(writer, &err, "%c", yy != 0 ? ' ' : '-');
 				}
 			}
 
-			bx::writePrintf(writer, "%s\n", yy != 0 ? "" : ">");
+			bx::write(writer, &err, "%s\n", yy != 0 ? "" : ">");
 		}
 	}
 }

+ 12 - 9
bx.mod/bx/tests/math_bench.cpp

@@ -25,8 +25,10 @@ float mathTest(const char* _name)
 		result += mfn(xx);
 	}
 
+	bx::Error err;
+
 	elapsed += bx::getHPCounter();
-	bx::writePrintf(writer, "%-20s: %15f\n", _name, double(elapsed) );
+	bx::write(writer, &err, "%-20s: %15f\n", _name, double(elapsed) );
 
 	return result;
 }
@@ -39,40 +41,41 @@ float rsqrt(float _a)
 void math_bench()
 {
 	bx::WriterI* writer = bx::getStdOut();
-	bx::writePrintf(writer, "Math bench\n\n");
+	bx::Error err;
+	bx::write(writer, &err, "Math bench\n\n");
 
 	mathTest<  ::sqrtf    >("  ::sqrtf");
 	mathTest<bx::sqrtRef  >("bx::sqrtRef");
 	mathTest<bx::sqrtSimd >("bx::sqrtSimd");
 	mathTest<bx::sqrt     >("bx::sqrt");
 
-	bx::writePrintf(writer, "\n");
+	bx::write(writer, &err, "\n");
 	mathTest<  ::rsqrt    >("  ::rsqrtf");
 	mathTest<bx::rsqrtRef >("bx::rsqrtRef");
 	mathTest<bx::rsqrtSimd>("bx::rsqrtSimd");
 	mathTest<bx::rsqrt    >("bx::rsqrt");
 
-	bx::writePrintf(writer, "\n");
+	bx::write(writer, &err, "\n");
 	mathTest<  ::sinf >("  ::sinf");
 	mathTest<bx::sin  >("bx::sin");
 
-	bx::writePrintf(writer, "\n");
+	bx::write(writer, &err, "\n");
 	mathTest<  ::asinf>("  ::asinf");
 	mathTest<bx::asin >("bx::asin");
 
-	bx::writePrintf(writer, "\n");
+	bx::write(writer, &err, "\n");
 	mathTest<  ::cosf >("  ::cosf");
 	mathTest<bx::cos  >("bx::cos");
 
-	bx::writePrintf(writer, "\n");
+	bx::write(writer, &err, "\n");
 	mathTest<  ::acosf>("  ::acosf");
 	mathTest<bx::acos >("bx::acos");
 
-	bx::writePrintf(writer, "\n");
+	bx::write(writer, &err, "\n");
 	mathTest<  ::tanf >("  ::tanf");
 	mathTest<bx::tan  >("bx::tan");
 
-	bx::writePrintf(writer, "\n");
+	bx::write(writer, &err, "\n");
 	mathTest<  ::atanf>("  ::atanf");
 	mathTest<bx::atan >("bx::atan");
 }

+ 43 - 29
bx.mod/bx/tests/math_test.cpp

@@ -55,84 +55,98 @@ TEST_CASE("libm", "")
 	REQUIRE(bx::equal( 0.89f, bx::fract( 13.89f), 0.000001f) );
 	REQUIRE(bx::equal(-0.89f, bx::fract(-13.89f), 0.000001f) );
 
+	bx::Error err;
+
 	for (int32_t yy = -10; yy < 10; ++yy)
 	{
 		for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
 		{
-			bx::writePrintf(writer, "ldexp(%f, %d) == %f (expected: %f)\n", xx, yy, bx::ldexp(xx, yy), ::ldexpf(xx, yy) );
+			bx::write(writer, &err, "ldexp(%f, %d) == %f (expected: %f)\n", xx, yy, bx::ldexp(xx, yy), ::ldexpf(xx, yy) );
 			REQUIRE(bx::equal(bx::ldexp(xx, yy), ::ldexpf(xx, yy), 0.00001f) );
 		}
 	}
 
 	for (float xx = -80.0f; xx < 80.0f; xx += 0.1f)
 	{
-		bx::writePrintf(writer, "exp(%f) == %f (expected: %f)\n", xx, bx::exp(xx), ::expf(xx) );
+		bx::write(writer, &err, "exp(%f) == %f (expected: %f)\n", xx, bx::exp(xx), ::expf(xx) );
+		REQUIRE(err.isOk() );
 		REQUIRE(bx::equal(bx::exp(xx), ::expf(xx), 0.00001f) );
 	}
 
 	for (float xx = 0.0f; xx < 100.0f; xx += 0.1f)
 	{
-		bx::writePrintf(writer, "rsqrt(%f) == %f (expected: %f)\n", xx, bx::rsqrt(xx), 1.0f/::sqrtf(xx) );
+		bx::write(writer, &err, "rsqrt(%f) == %f (expected: %f)\n", xx, bx::rsqrt(xx), 1.0f/::sqrtf(xx) );
+		REQUIRE(err.isOk() );
 		REQUIRE(bx::equal(bx::rsqrt(xx), 1.0f/::sqrtf(xx), 0.00001f) );
 	}
 
 	for (float xx = 0.0f; xx < 100.0f; xx += 0.1f)
 	{
-		bx::writePrintf(writer, "sqrt(%f) == %f (expected: %f)\n", xx, bx::sqrt(xx), ::sqrtf(xx) );
+		bx::write(writer, &err, "sqrt(%f) == %f (expected: %f)\n", xx, bx::sqrt(xx), ::sqrtf(xx) );
+		REQUIRE(err.isOk() );
 		REQUIRE(bx::equal(bx::sqrt(xx), ::sqrtf(xx), 0.00001f) );
 	}
 
 	for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
 	{
-		bx::writePrintf(writer, "pow(1.389f, %f) == %f (expected: %f)\n", xx, bx::pow(1.389f, xx), ::powf(1.389f, xx) );
+		bx::write(writer, &err, "pow(1.389f, %f) == %f (expected: %f)\n", xx, bx::pow(1.389f, xx), ::powf(1.389f, xx) );
+		REQUIRE(err.isOk() );
 		REQUIRE(bx::equal(bx::pow(1.389f, xx), ::powf(1.389f, xx), 0.00001f) );
 	}
 
 	for (float xx = -1.0f; xx < 1.0f; xx += 0.001f)
 	{
-		bx::writePrintf(writer, "asin(%f) == %f (expected: %f)\n", xx, bx::asin(xx), ::asinf(xx) );
+		bx::write(writer, &err, "asin(%f) == %f (expected: %f)\n", xx, bx::asin(xx), ::asinf(xx) );
+		REQUIRE(err.isOk() );
 		REQUIRE(bx::equal(bx::asin(xx), ::asinf(xx), 0.0001f) );
 	}
 
 	for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
 	{
-		bx::writePrintf(writer, "sin(%f) == %f (expected: %f)\n", xx, bx::sin(xx), ::sinf(xx) );
+		bx::write(writer, &err, "sin(%f) == %f (expected: %f)\n", xx, bx::sin(xx), ::sinf(xx) );
+		REQUIRE(err.isOk() );
 		REQUIRE(bx::equal(bx::sin(xx), ::sinf(xx), 0.00001f) );
 	}
 
 	for (float xx = -1.0f; xx < 1.0f; xx += 0.1f)
 	{
-		bx::writePrintf(writer, "sinh(%f) == %f (expected: %f)\n", xx, bx::sinh(xx), ::sinhf(xx) );
+		bx::write(writer, &err, "sinh(%f) == %f (expected: %f)\n", xx, bx::sinh(xx), ::sinhf(xx) );
+		REQUIRE(err.isOk() );
 		REQUIRE(bx::equal(bx::sinh(xx), ::sinhf(xx), 0.00001f) );
 	}
 
 	for (float xx = -1.0f; xx < 1.0f; xx += 0.001f)
 	{
-		bx::writePrintf(writer, "acos(%f) == %f (expected: %f\n)", xx, bx::acos(xx), ::acosf(xx) );
+		bx::write(writer, &err, "acos(%f) == %f (expected: %f\n)", xx, bx::acos(xx), ::acosf(xx) );
+		REQUIRE(err.isOk() );
 		REQUIRE(bx::equal(bx::acos(xx), ::acosf(xx), 0.0001f) );
 	}
 
 	for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
 	{
-		bx::writePrintf(writer, "cos(%f) == %f (expected: %f)\n", xx, bx::cos(xx), ::cosf(xx) );
+		bx::write(writer, &err, "cos(%f) == %f (expected: %f)\n", xx, bx::cos(xx), ::cosf(xx) );
+		REQUIRE(err.isOk() );
 		REQUIRE(bx::equal(bx::cos(xx), ::cosf(xx), 0.00001f) );
 	}
 
 	for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
 	{
-		bx::writePrintf(writer, "tan(%f) == %f (expected: %f)\n", xx, bx::tan(xx), ::tanf(xx) );
+		bx::write(writer, &err, "tan(%f) == %f (expected: %f)\n", xx, bx::tan(xx), ::tanf(xx) );
+		REQUIRE(err.isOk() );
 		REQUIRE(bx::equal(bx::tan(xx), ::tanf(xx), 0.001f) );
 	}
 
 	for (float xx = -1.0f; xx < 1.0f; xx += 0.1f)
 	{
-		bx::writePrintf(writer, "tanh(%f) == %f (expected: %f\n", xx, bx::tanh(xx), ::tanhf(xx) );
+		bx::write(writer, &err, "tanh(%f) == %f (expected: %f\n", xx, bx::tanh(xx), ::tanhf(xx) );
+		REQUIRE(err.isOk() );
 		REQUIRE(bx::equal(bx::tanh(xx), ::tanhf(xx), 0.00001f) );
 	}
 
 	for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
 	{
-		bx::writePrintf(writer, "atan(%f) == %f (expected: %f)\n", xx, bx::atan(xx), ::atanf(xx) );
+		bx::write(writer, &err, "atan(%f) == %f (expected: %f)\n", xx, bx::atan(xx), ::atanf(xx) );
+		REQUIRE(err.isOk() );
 		REQUIRE(bx::equal(bx::atan(xx), ::atanf(xx), 0.00001f) );
 	}
 
@@ -140,7 +154,8 @@ TEST_CASE("libm", "")
 	{
 		for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
 		{
-			bx::writePrintf(writer, "atan2(%f, %f) == %f (expected: %f)\n", yy, xx, bx::atan2(yy, xx), ::atan2f(yy, xx) );
+			bx::write(writer, &err, "atan2(%f, %f) == %f (expected: %f)\n", yy, xx, bx::atan2(yy, xx), ::atan2f(yy, xx) );
+			REQUIRE(err.isOk() );
 			REQUIRE(bx::equal(bx::atan2(yy, xx), ::atan2f(yy, xx), 0.00001f) );
 		}
 	}
@@ -188,8 +203,8 @@ TEST_CASE("quaternion", "")
 	float mtxQ[16];
 	float mtx[16];
 
-	float quat[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
-	bx::mtxQuat(mtxQ, quat);
+	bx::Quaternion quat = { 0.0f, 0.0f, 0.0f, 1.0f };
+	bx::mtxQuat(mtxQ, &quat.x);
 	bx::mtxIdentity(mtx);
 	mtxCheck(mtxQ, mtx);
 
@@ -197,28 +212,27 @@ TEST_CASE("quaternion", "")
 	float ay = bx::kPi/13.0f;
 	float az = bx::kPi/7.0f;
 
-	bx::quatRotateX(quat, ax);
-	bx::mtxQuat(mtxQ, quat);
+	quat = bx::rotateX(ax);
+	bx::mtxQuat(mtxQ, &quat.x);
 	bx::mtxRotateX(mtx, ax);
 	mtxCheck(mtxQ, mtx);
 
-	float euler[3];
-	bx::quatToEuler(euler, quat);
-	CHECK(bx::equal(euler[0], ax, 0.001f) );
+	bx::Vec3 euler = bx::toEuler(quat);
+	CHECK(bx::equal(euler.x, ax, 0.001f) );
 
-	bx::quatRotateY(quat, ay);
-	bx::mtxQuat(mtxQ, quat);
+	quat = bx::rotateY(ay);
+	bx::mtxQuat(mtxQ, &quat.x);
 	bx::mtxRotateY(mtx, ay);
 	mtxCheck(mtxQ, mtx);
 
-	bx::quatToEuler(euler, quat);
-	CHECK(bx::equal(euler[1], ay, 0.001f) );
+	euler = bx::toEuler(quat);
+	CHECK(bx::equal(euler.y, ay, 0.001f) );
 
-	bx::quatRotateZ(quat, az);
-	bx::mtxQuat(mtxQ, quat);
+	quat = bx::rotateZ(az);
+	bx::mtxQuat(mtxQ, &quat.x);
 	bx::mtxRotateZ(mtx, az);
 	mtxCheck(mtxQ, mtx);
 
-	bx::quatToEuler(euler, quat);
-	CHECK(bx::equal(euler[2], az, 0.001f) );
+	euler = bx::toEuler(quat);
+	CHECK(bx::equal(euler.z, az, 0.001f) );
 }

+ 195 - 0
bx.mod/bx/tests/nlalloc_test.cpp

@@ -0,0 +1,195 @@
+/*
+ * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ */
+
+#include "test.h"
+#include <bx/sort.h>
+#include <bx/allocator.h>
+
+bx::DefaultAllocator g_allocator0;
+
+struct TinyStlAllocator
+{
+	static void* static_allocate(size_t _bytes)
+	{
+		return BX_ALLOC(&g_allocator0, _bytes);
+	}
+
+	static void static_deallocate(void* _ptr, size_t /*_bytes*/)
+	{
+		if (NULL != _ptr)
+		{
+			BX_FREE(&g_allocator0, _ptr);
+		}
+	}
+};
+
+#define TINYSTL_ALLOCATOR ::TinyStlAllocator
+#include <tinystl/vector.h>
+
+namespace stl = tinystl;
+
+namespace bx
+{
+	struct Blk
+	{
+		static const uint64_t kInvalid = UINT64_MAX;
+
+		Blk()
+			: ptr(kInvalid)
+			, size(0)
+		{
+		}
+
+		Blk(uint64_t _ptr, uint32_t _size)
+			: ptr(_ptr)
+			, size(_size)
+		{
+		}
+
+		uint64_t ptr;
+		uint32_t size;
+	};
+
+	inline bool operator<(const Blk& _lhs, const Blk& _rhs)
+	{
+		return _lhs.ptr < _rhs.ptr;
+	}
+
+	inline bool isValid(const Blk& _blk)
+	{
+		return Blk::kInvalid != _blk.ptr;
+	}
+
+	// First-fit non-local allocator.
+	class NonLocalAllocator
+	{
+	public:
+		NonLocalAllocator()
+		{
+			reset();
+		}
+
+		~NonLocalAllocator()
+		{
+		}
+
+		void reset()
+		{
+			m_free.clear();
+			m_used = 0;
+		}
+
+		void add(const Blk& _blk)
+		{
+			m_free.push_back(_blk);
+		}
+
+		Blk remove()
+		{
+			BX_CHECK(0 == m_used, "");
+
+			if (0 < m_free.size() )
+			{
+				Blk freeBlock = m_free.back();
+				m_free.pop_back();
+				return freeBlock;
+			}
+
+			return Blk{};
+		}
+
+		Blk alloc(uint32_t _size)
+		{
+			_size = max(_size, 16u);
+
+			for (FreeList::iterator it = m_free.begin(), itEnd = m_free.end(); it != itEnd; ++it)
+			{
+				if (it->size >= _size)
+				{
+					uint64_t ptr = it->ptr;
+
+					if (it->size != _size)
+					{
+						it->size -= _size;
+						it->ptr  += _size;
+					}
+					else
+					{
+						m_free.erase(it);
+					}
+
+					m_used += _size;
+					return Blk{ ptr, _size };
+				}
+			}
+
+			// there is no block large enough.
+			return Blk{};
+		}
+
+		void free(const Blk& _blk)
+		{
+			m_used -= _blk.size;
+			m_free.push_back(_blk);
+			compact();
+		}
+
+		bool compact()
+		{
+			bx::quickSort(
+				  m_free.begin()
+				, uint32_t(m_free.end() - m_free.begin() )
+				, sizeof(Blk)
+				, [](const void* _a, const void* _b) -> int32_t {
+					const Blk& lhs = *(const Blk*)(_a);
+					const Blk& rhs = *(const Blk*)(_b);
+					return lhs < rhs ? -1 : 1;
+				});
+
+			for (FreeList::iterator it = m_free.begin(), next = it, itEnd = m_free.end(); next != itEnd;)
+			{
+				if ( (it->ptr + it->size) == next->ptr)
+				{
+					it->size += next->size;
+					next = m_free.erase(next);
+				}
+				else
+				{
+					it = next;
+					++next;
+				}
+			}
+
+			return 0 == m_used;
+		}
+
+		uint32_t getUsed() const
+		{
+			return m_used;
+		}
+
+	private:
+		typedef stl::vector<Blk> FreeList;
+		FreeList m_free;
+		uint32_t m_used;
+	};
+} // namespace bx
+
+TEST_CASE("nlalloc")
+{
+	bx::NonLocalAllocator nla;
+
+	bx::Blk blk;
+
+	blk = nla.alloc(100);
+	REQUIRE(!isValid(blk) );
+	nla.add(bx::Blk{0x1000, 100});
+
+	blk = nla.alloc(100);
+	REQUIRE(isValid(blk) );
+
+	nla.free(blk);
+	REQUIRE(0 == nla.getUsed() );
+}

+ 9 - 7
bx.mod/bx/tests/rng_test.cpp

@@ -41,38 +41,40 @@ void testRng(const char* _name, Ty* _rng)
 	}
 
 	bx::WriterI* writer = bx::getNullOut();
-	bx::writePrintf(writer, "%s\n", _name);
+	bx::Error err;
+
+	bx::write(writer, &err, "%s\n", _name);
 
 	{
-		bx::writePrintf(writer, "\tbits histogram:\n");
+		bx::write(writer, &err, "\tbits histogram:\n");
 		uint32_t min = UINT32_MAX;
 		uint32_t max = 0;
 
 		for (uint32_t ii = 0; ii < BX_COUNTOF(histBits); ++ii)
 		{
-			bx::writePrintf(writer, "\t\t%3d: %d\n", ii, histBits[ii]);
+			bx::write(writer, &err, "\t\t%3d: %d\n", ii, histBits[ii]);
 			min = bx::min(min, histBits[ii]);
 			max = bx::max(max, histBits[ii]);
 		}
 
-		bx::writePrintf(writer, "\tmin: %d, max: %d (diff: %d)\n", min, max, max-min);
+		bx::write(writer, &err, "\tmin: %d, max: %d (diff: %d)\n", min, max, max-min);
 
 		REQUIRE(max-min < 8000);
 	}
 
 	{
-		bx::writePrintf(writer, "\tuint8_t histogram:\n");
+		bx::write(writer, &err, "\tuint8_t histogram:\n");
 		uint32_t min = UINT32_MAX;
 		uint32_t max = 0;
 
 		for (uint32_t ii = 0; ii < BX_COUNTOF(histUint8); ++ii)
 		{
-			bx::writePrintf(writer, "\t\t%3d: %d\n", ii, histUint8[ii]);
+			bx::write(writer, &err, "\t\t%3d: %d\n", ii, histUint8[ii]);
 			min = bx::min(min, histUint8[ii]);
 			max = bx::max(max, histUint8[ii]);
 		}
 
-		bx::writePrintf(writer, "\tmin: %d, max: %d (diff: %d)\n", min, max, max-min);
+		bx::write(writer, &err, "\tmin: %d, max: %d (diff: %d)\n", min, max, max-min);
 
 		REQUIRE(max-min < 8000);
 	}

+ 3 - 3
bx.mod/bx/tests/settings_test.cpp

@@ -27,12 +27,12 @@ TEST_CASE("Settings", "")
 		bx::close(&writer);
 	}
 
-	REQUIRE(NULL == settings.get("meh") );
+	REQUIRE(settings.get("meh").isEmpty() );
 	REQUIRE(0 == bx::strCmp(settings.get("meh/podmac"), "true") );
 	REQUIRE(0 == bx::strCmp(settings.get("test/foo/bar/abvgd"), "1389") );
 
 	settings.remove("meh/podmac");
-	REQUIRE(NULL == settings.get("meh/podmac") );
+	REQUIRE(settings.get("meh/podmac").isEmpty() );
 
 	settings.clear();
 
@@ -43,7 +43,7 @@ TEST_CASE("Settings", "")
 		bx::close(&reader);
 	}
 
-	REQUIRE(NULL == settings.get("meh") );
+	REQUIRE(settings.get("meh").isEmpty() );
 	REQUIRE(0 == bx::strCmp(settings.get("meh/podmac"), "true") );
 	REQUIRE(0 == bx::strCmp(settings.get("test/foo/bar/abvgd"), "1389") );
 }

+ 1 - 1
bx.mod/bx/tests/simd_bench.cpp

@@ -111,7 +111,7 @@ void simd_bench()
 	for (uint32_t ii = 0; ii < numVertices; ++ii)
 	{
 		float* ptr = (float*)&src[ii];
-		randUnitSphere(ptr, &rng);
+		bx::store(ptr, bx::randUnitSphere(&rng) );
 		ptr[3] = 1.0f;
 	}
 

+ 131 - 56
bx.mod/bx/tests/string_test.cpp

@@ -181,19 +181,19 @@ TEST_CASE("strCmpV sort", "")
 TEST_CASE("strRFind", "")
 {
 	const char* test = "test";
-	REQUIRE(NULL == bx::strRFind(bx::StringView(test, 0), 's') );
-	REQUIRE(NULL == bx::strRFind(bx::StringView(test, 1), 's') );
-	REQUIRE(&test[2] == bx::strRFind(test, 's') );
+	REQUIRE(bx::strRFind(bx::StringView(test, 0), 's').isEmpty() );
+	REQUIRE(bx::strRFind(bx::StringView(test, 1), 's').isEmpty() );
+	REQUIRE(&test[2] == bx::strRFind(test, 's').getPtr() );
 }
 
 TEST_CASE("strFindI", "")
 {
 	const char* test = "The Quick Brown Fox Jumps Over The Lazy Dog.";
 
-	REQUIRE(NULL == bx::strFindI(bx::StringView(test, 8), "quick") );
-	REQUIRE(NULL == bx::strFindI(test, "quick1") );
-	REQUIRE(&test[4] == bx::strFindI(bx::StringView(test, 9), "quick") );
-	REQUIRE(&test[4] == bx::strFindI(test, "quick") );
+	REQUIRE(bx::strFindI(bx::StringView(test, 8), "quick").isEmpty() );
+	REQUIRE(bx::strFindI(test, "quick1").isEmpty() );
+	REQUIRE(&test[4] == bx::strFindI(bx::StringView(test, 9), "quick").getPtr() );
+	REQUIRE(&test[4] == bx::strFindI(test, "quick").getPtr() );
 }
 
 TEST_CASE("strFind", "")
@@ -201,33 +201,49 @@ TEST_CASE("strFind", "")
 	{
 		const char* test = "test";
 
-		REQUIRE(NULL == bx::strFind(bx::StringView(test, 0), 's') );
-		REQUIRE(NULL == bx::strFind(bx::StringView(test, 2), 's') );
-		REQUIRE(&test[2] == bx::strFind(test, 's') );
+		REQUIRE(bx::strFind(bx::StringView(test, 0), 's').isEmpty() );
+		REQUIRE(bx::strFind(bx::StringView(test, 2), 's').isEmpty() );
+		REQUIRE(&test[2] == bx::strFind(test, 's').getPtr() );
 	}
 
 	{
 		const char* test = "The Quick Brown Fox Jumps Over The Lazy Dog.";
 
-		REQUIRE(NULL == bx::strFind(bx::StringView(test, 8), "quick") );
-		REQUIRE(NULL == bx::strFind(test, "quick1") );
-		REQUIRE(NULL == bx::strFind(bx::StringView(test, 9), "quick") );
-		REQUIRE(NULL == bx::strFind(test, "quick") );
+		REQUIRE(bx::strFind(bx::StringView(test, 8), "quick").isEmpty() );
+		REQUIRE(bx::strFind(test, "quick1").isEmpty() );
+		REQUIRE(bx::strFind(bx::StringView(test, 9), "quick").isEmpty() );
+		REQUIRE(bx::strFind(test, "quick").isEmpty() );
 
-		REQUIRE(NULL == bx::strFind(bx::StringView(test, 8), "Quick") );
-		REQUIRE(NULL == bx::strFind(test, "Quick1") );
-		REQUIRE(&test[4] == bx::strFind(bx::StringView(test, 9), "Quick") );
-		REQUIRE(&test[4] == bx::strFind(test, "Quick") );
+		REQUIRE(bx::strFind(bx::StringView(test, 8), "Quick").isEmpty() );
+		REQUIRE(bx::strFind(test, "Quick1").isEmpty() );
+		REQUIRE(&test[4] == bx::strFind(bx::StringView(test, 9), "Quick").getPtr() );
+		REQUIRE(&test[4] == bx::strFind(test, "Quick").getPtr() );
 
-		REQUIRE(NULL == bx::strFind("vgd", 'a') );
+		REQUIRE(bx::strFind("vgd", 'a').isEmpty() );
 	}
 }
 
+TEST_CASE("strSkip", "")
+{
+	const bx::StringView t0("   test X");
+
+	const bx::StringView t1 = bx::strLTrimSpace(t0);
+	REQUIRE(0 == bx::strCmp(t1, "test", 4) );
+
+	const bx::StringView t2 = bx::strLTrimNonSpace(t1);
+	REQUIRE(0 == bx::strCmp(t2, " X", 2) );
+
+	const bx::StringView t3("test");
+
+	const bx::StringView t4 = bx::strLTrimNonSpace(t3);
+	REQUIRE(t4.getTerm() == t4.getPtr() );
+}
+
 template<typename Ty>
-static bool testToString(Ty _value, const char* _expected)
+static bool testToStringS(Ty _value, const char* _expected, char _separator = '\0')
 {
 	char tmp[1024];
-	int32_t num = bx::toString(tmp, BX_COUNTOF(tmp), _value);
+	int32_t num = bx::toString(tmp, BX_COUNTOF(tmp), _value, 10, _separator);
 	int32_t len = (int32_t)bx::strLen(_expected);
 	if (0 == bx::strCmp(tmp, _expected)
 	&&  num == len)
@@ -239,12 +255,37 @@ static bool testToString(Ty _value, const char* _expected)
 	return false;
 }
 
-TEST_CASE("toString int32_t/uint32_t", "")
+TEST_CASE("toString intXX_t/uintXX_t", "")
 {
-	REQUIRE(testToString(0,          "0") );
-	REQUIRE(testToString(-256,       "-256") );
-	REQUIRE(testToString(INT32_MAX,  "2147483647") );
-	REQUIRE(testToString(UINT32_MAX, "4294967295") );
+	REQUIRE(testToStringS(0,          "0") );
+	REQUIRE(testToStringS(-256,       "-256") );
+	REQUIRE(testToStringS(INT32_MAX,  "2147483647") );
+	REQUIRE(testToStringS(UINT32_MAX, "4294967295") );
+	REQUIRE(testToStringS(INT64_MAX,  "9223372036854775807") );
+	REQUIRE(testToStringS(UINT64_MAX, "18446744073709551615") );
+
+	REQUIRE(testToStringS(0,          "0", ',') );
+	REQUIRE(testToStringS(-256,       "-256", ',') );
+	REQUIRE(testToStringS(INT32_MAX,  "2,147,483,647", ',') );
+	REQUIRE(testToStringS(UINT32_MAX, "4,294,967,295", ',') );
+	REQUIRE(testToStringS(INT64_MAX,  "9,223,372,036,854,775,807", ',') );
+	REQUIRE(testToStringS(UINT64_MAX, "18,446,744,073,709,551,615", ',') );
+}
+
+template<typename Ty>
+static bool testToString(Ty _value, const char* _expected)
+{
+	char tmp[1024];
+	int32_t num = bx::toString(tmp, BX_COUNTOF(tmp), _value);
+	int32_t len = (int32_t)bx::strLen(_expected);
+	if (0 == bx::strCmp(tmp, _expected)
+	&&  num == len)
+	{
+		return true;
+	}
+
+	printf("result '%s' (%d), expected '%s' (%d)\n", tmp, num, _expected, len);
+	return false;
 }
 
 TEST_CASE("toString double", "")
@@ -277,15 +318,16 @@ TEST_CASE("toString double", "")
 	REQUIRE(testToString(-79.39773355813419,      "-79.39773355813419") );
 }
 
-static bool testFromString(double _value, const char* _input)
+template<typename Ty>
+static bool testFromString(Ty _value, const char* _input)
 {
 	char tmp[1024];
 	bx::toString(tmp, BX_COUNTOF(tmp), _value);
 
-	double lhs;
+	Ty lhs;
 	bx::fromString(&lhs, tmp);
 
-	double rhs;
+	Ty rhs;
 	bx::fromString(&rhs, _input);
 
 	if (lhs == rhs)
@@ -297,33 +339,57 @@ static bool testFromString(double _value, const char* _input)
 	return false;
 }
 
+TEST_CASE("fromString float", "")
+{
+	REQUIRE(testFromString<float>(std::numeric_limits<float>::min(),    "1.175494351e-38") );
+	REQUIRE(testFromString<float>(std::numeric_limits<float>::lowest(), "-3.402823466e+38") );
+	REQUIRE(testFromString<float>(std::numeric_limits<float>::max(),    "3.402823466e+38") );
+}
+
 TEST_CASE("fromString double", "")
 {
-	REQUIRE(testFromString(0.0,                     "0.0") );
-	REQUIRE(testFromString(-0.0,                    "-0.0") );
-	REQUIRE(testFromString(1.0,                     "1.0") );
-	REQUIRE(testFromString(-1.0,                    "-1.0") );
-	REQUIRE(testFromString(1.2345,                  "1.2345") );
-	REQUIRE(testFromString(1.2345678,               "1.2345678") );
-	REQUIRE(testFromString(0.123456789012,          "0.123456789012") );
-	REQUIRE(testFromString(1234567.8,               "1234567.8") );
-	REQUIRE(testFromString(-79.39773355813419,      "-79.39773355813419") );
-	REQUIRE(testFromString(0.000001,                "0.000001") );
-	REQUIRE(testFromString(0.0000001,               "1e-7") );
-	REQUIRE(testFromString(1e30,                    "1e30") );
-	REQUIRE(testFromString(1.234567890123456e30,    "1.234567890123456e30") );
-	REQUIRE(testFromString(-5e-324,                 "-5e-324") );
-	REQUIRE(testFromString(2.225073858507201e-308,  "2.225073858507201e-308") );
-	REQUIRE(testFromString(2.2250738585072014e-308, "2.2250738585072014e-308") );
-	REQUIRE(testFromString(1.7976931348623157e308,  "1.7976931348623157e308") );
-	REQUIRE(testFromString(0.00000123123123,        "0.00000123123123") );
-	REQUIRE(testFromString(0.000000123123123,       "1.23123123e-7") );
-	REQUIRE(testFromString(123123.123,              "123123.123") );
-	REQUIRE(testFromString(1231231.23,              "1231231.23") );
-	REQUIRE(testFromString(0.000000000123123,       "1.23123e-10") );
-	REQUIRE(testFromString(0.0000000001,            "1e-10") );
-	REQUIRE(testFromString(-270.000000,             "-270.0") );
-	REQUIRE(testFromString(2.2250738585072011e-308, "2.2250738585072011e-308") );
+	REQUIRE(testFromString<double>(0.0,                     "0.0") );
+	REQUIRE(testFromString<double>(-0.0,                    "-0.0") );
+	REQUIRE(testFromString<double>(1.0,                     "1.0") );
+	REQUIRE(testFromString<double>(-1.0,                    "-1.0") );
+	REQUIRE(testFromString<double>(1.2345,                  "1.2345") );
+	REQUIRE(testFromString<double>(1.2345678,               "1.2345678") );
+	REQUIRE(testFromString<double>(0.123456789012,          "0.123456789012") );
+	REQUIRE(testFromString<double>(123456.789,              "123456.789") );
+	REQUIRE(testFromString<double>(1234567.8,               "1234567.8") );
+	REQUIRE(testFromString<double>(-79.39773355813419,      "-79.39773355813419") );
+	REQUIRE(testFromString<double>(0.000001,                "0.000001") );
+	REQUIRE(testFromString<double>(0.0000001,               "1e-7") );
+	REQUIRE(testFromString<double>(1e30,                    "1e30") );
+	REQUIRE(testFromString<double>(1.234567890123456e30,    "1.234567890123456e30") );
+	REQUIRE(testFromString<double>(-5e-324,                 "-5e-324") );
+	REQUIRE(testFromString<double>(2.225073858507201e-308,  "2.225073858507201e-308") );
+	REQUIRE(testFromString<double>(2.2250738585072014e-308, "2.2250738585072014e-308") );
+	REQUIRE(testFromString<double>(1.7976931348623157e308,  "1.7976931348623157e308") );
+	REQUIRE(testFromString<double>(0.00000123123123,        "0.00000123123123") );
+	REQUIRE(testFromString<double>(0.000000123123123,       "1.23123123e-7") );
+	REQUIRE(testFromString<double>(123123.123,              "123123.123") );
+	REQUIRE(testFromString<double>(1231231.23,              "1231231.23") );
+	REQUIRE(testFromString<double>(0.000000000123123,       "1.23123e-10") );
+	REQUIRE(testFromString<double>(0.0000000001,            "1e-10") );
+	REQUIRE(testFromString<double>(-270.000000,             "-270.0") );
+	REQUIRE(testFromString<double>(2.2250738585072011e-308, "2.2250738585072011e-308") ); // https://web.archive.org/web/20181112222123/https://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+	REQUIRE(testFromString<double>(2.2250738585072009e-308, "2.2250738585072009e-308") ); // Max subnormal double
+	REQUIRE(testFromString<double>(4.9406564584124654e-324, "4.9406564584124654e-324") ); // Min denormal
+	REQUIRE(testFromString<double>(1.7976931348623157e+308, "1.7976931348623157e+308") ); // Max double
+
+//  warning: magnitude of floating-point constant too small for type 'double'; minimum is 4.9406564584124654E-324
+//	REQUIRE(testFromString<double>(1e-10000,                "0.0") );                     // Must underflow
+//	integer literal is too large to be represented in any integer type
+//	REQUIRE(testFromString<double>(18446744073709551616,    "18446744073709551616.0") );  // 2^64 (max of uint64_t + 1, force to use double)
+//	REQUIRE(testFromString<double>(-9223372036854775809,    "-9223372036854775809.0") );  // -2^63 - 1(min of int64_t + 1, force to use double)
+
+	REQUIRE(testFromString<double>(0.9868011474609375,      "0.9868011474609375") );      // https://github.com/miloyip/rapidjson/issues/120
+	REQUIRE(testFromString<double>(123e34,                  "123e34") );
+	REQUIRE(testFromString<double>(45913141877270640000.0,  "45913141877270640000.0") );
+	REQUIRE(testFromString<double>(std::numeric_limits<double>::min(),    "2.2250738585072014e-308") );
+	REQUIRE(testFromString<double>(std::numeric_limits<double>::lowest(), "-1.7976931348623158e+308") );
+	REQUIRE(testFromString<double>(std::numeric_limits<double>::max(),    "1.7976931348623158e+308") );
 }
 
 static bool testFromString(int32_t _value, const char* _input)
@@ -392,11 +458,11 @@ TEST_CASE("StringView", "")
 TEST_CASE("Trim", "")
 {
 	REQUIRE(0 == bx::strCmp(bx::strLTrim("abvgd", "ab"), "vgd") );
-	REQUIRE(0 == bx::strCmp(bx::strLTrim("abvgd", "vagbd"), "") );
+	REQUIRE(0 == bx::strCmp(bx::strLTrim("abvgd", "vagbd"), "abvgd") );
 	REQUIRE(0 == bx::strCmp(bx::strLTrim("abvgd", "vgd"), "abvgd") );
 	REQUIRE(0 == bx::strCmp(bx::strLTrim("/555333/podmac/", "/"), "555333/podmac/") );
 
-	REQUIRE(0 == bx::strCmp(bx::strRTrim("abvgd", "vagbd"), "") );
+	REQUIRE(0 == bx::strCmp(bx::strRTrim("abvgd", "vagbd"), "abvgd") );
 	REQUIRE(0 == bx::strCmp(bx::strRTrim("abvgd", "abv"), "abvgd") );
 	REQUIRE(0 == bx::strCmp(bx::strRTrim("/555333/podmac/", "/"), "/555333/podmac") );
 
@@ -416,3 +482,12 @@ TEST_CASE("strWord", "")
 	REQUIRE(bx::strWord(" abvgd-1389.0").isEmpty() );
 	REQUIRE(0 == bx::strCmp(bx::strWord("abvgd-1389.0"), "abvgd") );
 }
+
+TEST_CASE("strFindBlock", "")
+{
+	const bx::StringView test0("{ { {} {} abvgd; {} } }");
+	const bx::StringView test1(test0, 1);
+
+	bx::StringView result = bx::strFindBlock(test1, '{', '}');
+	REQUIRE(19 == result.getLength() );
+}

+ 13 - 8
bx.mod/bx/tests/uint32_test.cpp

@@ -24,25 +24,18 @@ TEST_CASE("StrideAlign")
 TEST_CASE("uint32_cnt")
 {
 	REQUIRE( 0 == bx::uint32_cnttz(UINT32_C(1) ) );
-	REQUIRE( 0 == bx::uint32_cnttz_ref(UINT32_C(1) ) );
 
 	REQUIRE(31 == bx::uint32_cntlz(UINT32_C(1) ) );
-	REQUIRE(31 == bx::uint32_cntlz_ref(UINT32_C(1) ) );
 
 	REQUIRE( 0 == bx::uint64_cnttz(UINT64_C(1) ) );
-	REQUIRE( 0 == bx::uint64_cnttz_ref(UINT64_C(1) ) );
 
 	REQUIRE(63 == bx::uint64_cntlz(UINT64_C(1) ) );
-	REQUIRE(63 == bx::uint64_cntlz_ref(UINT64_C(1) ) );
 
 	REQUIRE( 1 == bx::uint32_cntbits(1) );
-	REQUIRE( 1 == bx::uint32_cntbits_ref(1) );
 
 	REQUIRE(16 == bx::uint32_cntbits(UINT16_MAX) );
-	REQUIRE(16 == bx::uint32_cntbits_ref(UINT16_MAX) );
 
 	REQUIRE(32 == bx::uint32_cntbits(UINT32_MAX) );
-	REQUIRE(32 == bx::uint32_cntbits_ref(UINT32_MAX) );
 }
 
 TEST_CASE("uint32_part")
@@ -78,8 +71,20 @@ TEST_CASE("uint32_testpow2", "")
 	{
 		if (bx::uint32_testpow2(ii) )
 		{
-			REQUIRE(ii == 1 << shift);
+			REQUIRE(ii == 1u << shift);
 			++shift;
 		}
 	}
 }
+
+TEST_CASE("uint32_roX", "")
+{
+	REQUIRE(bx::uint32_rol(0x80000000, 1) == 1);
+	REQUIRE(bx::uint32_ror(1, 1) == 0x80000000);
+}
+
+TEST_CASE("uint64_roX", "")
+{
+	REQUIRE(bx::uint64_rol(0x8000000000000000, 1) == 1);
+	REQUIRE(bx::uint64_ror(1, 1) == 0x8000000000000000);
+}

+ 42 - 32
bx.mod/bx/tests/vsnprintf_test.cpp

@@ -5,6 +5,8 @@
 
 #include "test.h"
 #include <bx/string.h>
+#include <bx/readerwriter.h>
+
 #include <limits>
 #include <inttypes.h>
 
@@ -17,10 +19,13 @@ TEST_CASE("vsnprintf NULL buffer", "No output buffer provided.")
 
 TEST_CASE("vsnprintf truncated", "Truncated output buffer.")
 {
-	char buffer[7];
+	char buffer5[5]; // fit
+	REQUIRE(4 == bx::snprintf(buffer5, BX_COUNTOF(buffer5), "abvg") );
+	REQUIRE(0 == bx::strCmp(buffer5, "abvg") );
 
-	REQUIRE(10 == bx::snprintf(buffer, BX_COUNTOF(buffer), "Ten chars!") );
-	REQUIRE(0  == bx::strCmp(buffer, "Ten ch") );
+	char buffer7[7]; // truncate
+	REQUIRE(10 == bx::snprintf(buffer7, BX_COUNTOF(buffer7), "Ten chars!") );
+	REQUIRE(0  == bx::strCmp(buffer7, "Ten ch") );
 }
 
 static bool test(const char* _expected, const char* _format, ...)
@@ -46,7 +51,7 @@ static bool test(const char* _expected, const char* _format, ...)
 	return result;
 }
 
-TEST_CASE("vsnprintf f", "")
+TEST_CASE("vsnprintf f")
 {
 	REQUIRE(test("1.337",    "%0.3f", 1.337) );
 	REQUIRE(test("  13.370", "%8.3f", 13.37) );
@@ -56,23 +61,14 @@ TEST_CASE("vsnprintf f", "")
 
 	REQUIRE(test("nan     ", "%-8f",  std::numeric_limits<double>::quiet_NaN() ) );
 	REQUIRE(test("     nan", "%8f",   std::numeric_limits<double>::quiet_NaN() ) );
-
-#if !BX_CRT_MSVC
-	// BK - VS2015 CRT vsnprintf returns '-NAN(IND'.
-#	if BX_CRT_LIBCXX
-	// BK - Clang LibC vsnprintf returns 'NAN     '.
-	REQUIRE(test("NAN     ", "%-8F", -std::numeric_limits<double>::quiet_NaN() ) );
-#	else
 	REQUIRE(test("-NAN    ", "%-8F", -std::numeric_limits<double>::quiet_NaN() ) );
-#	endif // BX_CRT_LIBCXX
-#endif // !BX_CRT_MSVC
 
 	REQUIRE(test("     inf", "%8f",   std::numeric_limits<double>::infinity() ) );
 	REQUIRE(test("inf     ", "%-8f",  std::numeric_limits<double>::infinity() ) );
 	REQUIRE(test("    -INF", "%8F",  -std::numeric_limits<double>::infinity() ) );
 }
 
-TEST_CASE("vsnprintf d/i/o/u/x", "")
+TEST_CASE("vsnprintf d/i/o/u/x")
 {
 	REQUIRE(test("1337", "%d", 1337) );
 	REQUIRE(test("1337                ", "%-20d",  1337) );
@@ -101,8 +97,6 @@ TEST_CASE("vsnprintf d/i/o/u/x", "")
 	REQUIRE(test("000000000000edcb5433", "%020x", -0x1234abcd) );
 	REQUIRE(test("000000000000EDCB5433", "%020X", -0x1234abcd) );
 
-#if !BX_CRT_MSVC
-	// BK - VS2015 CRT vsnprintf doesn't support 'j' length sub-specifier?
 	if (BX_ENABLED(BX_ARCH_32BIT) )
 	{
 		REQUIRE(test("2147483647", "%jd", INTMAX_MAX) );
@@ -111,13 +105,12 @@ TEST_CASE("vsnprintf d/i/o/u/x", "")
 	{
 		REQUIRE(test("9223372036854775807", "%jd", INTMAX_MAX) );
 	}
-#endif // !BX_CRT_MSVC
 
 	REQUIRE(test("18446744073709551615", "%" PRIu64, UINT64_MAX) );
 	REQUIRE(test("ffffffffffffffff", "%016" PRIx64, UINT64_MAX) );
 }
 
-TEST_CASE("vsnprintf modifiers", "")
+TEST_CASE("vsnprintf modifiers")
 {
 	REQUIRE(test("|  1.000000|", "|%10f|",      1.0f) );
 	REQUIRE(test("|1.000000  |", "|%-10f|",     1.0f) );
@@ -132,36 +125,53 @@ TEST_CASE("vsnprintf modifiers", "")
 	REQUIRE(test("|+1.       |", "|%+#-10.0f|", 1.0f) );
 }
 
-TEST_CASE("vsnprintf p", "")
+TEST_CASE("vsnprintf p")
 {
-#if BX_CRT_MSVC
-	// BK - VS2015 CRT vsnprintf has different output for 'p' pointer specifier.
-	REQUIRE(test("0BADC0DE", "%p", (void*)0xbadc0de));
-	REQUIRE(test("0BADC0DE            ", "%-20p", (void*)0xbadc0de));
-#else
 	REQUIRE(test("0xbadc0de", "%p", (void*)0xbadc0de) );
 	REQUIRE(test("0xbadc0de           ", "%-20p", (void*)0xbadc0de) );
-#endif // BX_CRT_MSVC
 }
 
-TEST_CASE("vsnprintf s", "")
+TEST_CASE("vsnprintf s")
 {
 	REQUIRE(test("(null)", "%s", NULL) );
 }
 
-TEST_CASE("vsnprintf g", "")
+TEST_CASE("vsnprintf g")
 {
-	REQUIRE(test("   0.01",  "%7.3g", .01) );
-	REQUIRE(test(" 0.0123",  "%7.3G", .0123) );
-	REQUIRE(test("1.23e+05", "%.3g",  123000.25) );
-	REQUIRE(test("1e+05",    "%.0g",  123000.25) );
+	REQUIRE(test("   0.01",  "%7.2g", .01) );
+	REQUIRE(test(" 0.0123",  "%7.4G", .0123) );
+//	REQUIRE(test("1.23e+05", "%.3g",  123000.25) );
+//	REQUIRE(test("1e+05",    "%.0g",  123000.25) );
 }
 
-TEST_CASE("vsnprintf", "")
+TEST_CASE("vsnprintf")
 {
 	REQUIRE(test("x", "%c", 'x') );
 	REQUIRE(test("x                   ", "%-20c", 'x') );
 
 	REQUIRE(test("hello               ", "%-20s", "hello") );
 	REQUIRE(test("hello, world!", "%s, %s!", "hello", "world") );
+
+	bx::StringView str("0hello1world2");
+	bx::StringView hello(str, 1, 5);
+	bx::StringView world(str, 7, 5);
+	REQUIRE(test("hello, world!", "%.*s, %.*s!"
+		, hello.getLength(), hello.getPtr()
+		, world.getLength(), world.getPtr()
+		) );
+}
+
+TEST_CASE("vsnprintf write")
+{
+	char tmp[64];
+	bx::StaticMemoryBlock mb(tmp, sizeof(tmp));
+	bx::MemoryWriter writer(&mb);
+
+	bx::Error err;
+	int32_t len = bx::write(&writer, &err, "%d", 1389);
+	REQUIRE(err.isOk());
+	REQUIRE(len == 4);
+
+	bx::StringView str(tmp, len);
+	REQUIRE(0 == bx::strCmp(str, "1389") );
 }

+ 17 - 1
bx.mod/glue.cpp

@@ -75,7 +75,23 @@ void bmx_bx_mtxQuatTranslationHMD(float * result, float * quat, float * translat
 }
 
 void bmx_bx_mtxLookAt(float * result, float * eye, float * at, float * up) {
-	bx::mtxLookAt(result, eye, at, up);
+	bx::Vec3 vEye;
+	bx::Vec3 vAt;
+	bx::Vec3 vUp;
+	bx::mtxLookAt(result, vEye, vAt, vUp);
+	eye[0] = vEye.x;
+	eye[1] = vEye.y;
+	eye[2] = vEye.z;
+
+	at[0] = vAt.x;
+	at[1] = vAt.y;
+	at[2] = vAt.z;
+	
+	if (up) {
+		up[0] = vUp.x;
+		up[1] = vUp.y;
+		up[2] = vUp.z;
+	}
 }
 
 //void bmx_bx_mtxProjXYWH(float * result, float x, float y, float width, float height, float near, float far, int oglNdc) {