Initial commit

This commit is contained in:
Martin Felis
2021-11-11 21:22:24 +01:00
commit b78045ffe7
812 changed files with 421882 additions and 0 deletions
@@ -0,0 +1,41 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_DEQUE_H_
#define OZZ_OZZ_BASE_CONTAINERS_DEQUE_H_
#include <deque>
#include "ozz/base/containers/std_allocator.h"
namespace ozz {
// Redirects std::deque to ozz::deque in order to replace std default allocator
// by ozz::StdAllocator.
template <class _Ty, class _Allocator = ozz::StdAllocator<_Ty>>
using deque = std::deque<_Ty, _Allocator>;
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_DEQUE_H_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,51 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_LIST_H_
#define OZZ_OZZ_BASE_CONTAINERS_LIST_H_
#ifdef _MSC_VER
#pragma warning(push)
// Removes constant conditional expression warning.
#pragma warning(disable : 4127)
#endif // _MSC_VER
#include <list>
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
#include "ozz/base/containers/std_allocator.h"
namespace ozz {
// Redirects std::list to ozz::list in order to replace std default allocator by
// ozz::StdAllocator.
template <class _Ty, class _Allocator = ozz::StdAllocator<_Ty>>
using list = std::list<_Ty, _Allocator>;
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_LIST_H_
@@ -0,0 +1,70 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_MAP_H_
#define OZZ_OZZ_BASE_CONTAINERS_MAP_H_
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4702) // warning C4702: unreachable code
#endif // _MSC_VER
#include <cstring>
#include <map>
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
#include "ozz/base/containers/std_allocator.h"
namespace ozz {
// Redirects std::map to ozz::map in order to replace std default allocator by
// ozz::StdAllocator.
template <class _Key, class _Ty, class _Pred = std::less<_Key>,
class _Allocator = ozz::StdAllocator<std::pair<const _Key, _Ty>>>
using map = std::map<_Key, _Ty, _Pred, _Allocator>;
// Implements a string comparator that can be used by std algorithm like maps.
struct str_less {
bool operator()(const char* const& _left, const char* const& _right) const {
return strcmp(_left, _right) < 0;
}
};
// Specializes std::map to use c-string as a key.
template <class _Ty, class _Allocator =
ozz::StdAllocator<std::pair<const char* const, _Ty>>>
using cstring_map = std::map<const char*, _Ty, str_less, _Allocator>;
// Redirects std::multimap to ozz::MultiMap in order to replace std default
// allocator by ozz::StdAllocator.
template <class _Key, class _Ty, class _Pred = std::less<_Key>,
class _Allocator = ozz::StdAllocator<std::pair<const _Key, _Ty>>>
using multimap = std::multimap<_Key, _Ty, _Pred, _Allocator>;
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_MAP_H_
@@ -0,0 +1,47 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_QUEUE_H_
#define OZZ_OZZ_BASE_CONTAINERS_QUEUE_H_
#include <queue>
#include "deque.h"
namespace ozz {
// Redirects std::queue to ozz::queue in order to replace std default allocator
// by ozz::StdAllocator.
template <class _Ty, class _Container = deque<_Ty>>
using queue = std::queue<_Ty, _Container>;
// Redirects std::priority_queue to ozz::priority_queue in order to replace std
// default allocator by ozz::StdAllocator.
template <class _Ty, class _Container = deque<_Ty>,
class _Pred = std::less<typename _Container::value_type>>
using priority_queue = std::priority_queue<_Ty, _Container, _Pred>;
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_QUEUE_H_
@@ -0,0 +1,48 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_SET_H_
#define OZZ_OZZ_BASE_CONTAINERS_SET_H_
#include <set>
#include "ozz/base/containers/std_allocator.h"
namespace ozz {
// Redirects std::set to ozz::set in order to replace std default allocator by
// ozz::StdAllocator.
template <class _Key, class _Pred = std::less<_Key>,
class _Allocator = ozz::StdAllocator<_Key>>
using set = std::set<_Key, _Pred, _Allocator>;
// Redirects std::multiset to ozz::multiset in order to replace std default
// allocator by ozz::StdAllocator.
template <class _Key, class _Pred = std::less<_Key>,
class _Allocator = ozz::StdAllocator<_Key>>
using multiset = std::multiset<_Key, _Pred, _Allocator>;
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_SET_H_
@@ -0,0 +1,41 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_STACK_H_
#define OZZ_OZZ_BASE_CONTAINERS_STACK_H_
#include <stack>
#include "deque.h"
namespace ozz {
// Redirects std::stack to ozz::stack in order to replace std default allocator
// by ozz::StdAllocator.
template <class _Ty, class _Container = typename ozz::deque<_Ty>>
using stack = std::stack<_Ty, _Container>;
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_STACK_H_
@@ -0,0 +1,105 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_STD_ALLOCATOR_H_
#define OZZ_OZZ_BASE_CONTAINERS_STD_ALLOCATOR_H_
#include <new>
#include "ozz/base/memory/allocator.h"
namespace ozz {
// Define a STL allocator compliant allocator->
template <typename _Ty>
class StdAllocator {
public:
typedef _Ty value_type; // Element type.
typedef value_type* pointer; // Pointer to element.
typedef value_type& reference; // Reference to element.
typedef const value_type* const_pointer; // Constant pointer to element.
typedef const value_type& const_reference; // Constant reference to element.
typedef size_t size_type; // Quantities of elements.
typedef ptrdiff_t difference_type; // Difference between two pointers.
StdAllocator() noexcept {}
StdAllocator(const StdAllocator&) noexcept {}
template <class _Other>
StdAllocator<value_type>(const StdAllocator<_Other>&) noexcept {}
template <class _Other>
struct rebind {
typedef StdAllocator<_Other> other;
};
pointer address(reference _ref) const noexcept { return &_ref; }
const_pointer address(const_reference _ref) const noexcept { return &_ref; }
template <class _Other, class... _Args>
void construct(_Other* _ptr, _Args&&... _args) {
::new (static_cast<void*>(_ptr)) _Other(std::forward<_Args>(_args)...);
}
template <class _Other>
void destroy(_Other* _ptr) {
(void)_ptr;
_ptr->~_Other();
}
// Allocates array of _Count elements.
pointer allocate(size_t _count) noexcept {
// Makes sure to a use c like allocator, to avoid duplicated constructor
// calls.
return reinterpret_cast<pointer>(memory::default_allocator()->Allocate(
sizeof(value_type) * _count, alignof(value_type)));
}
// Deallocates object at _Ptr, ignores size.
void deallocate(pointer _ptr, size_type) noexcept {
memory::default_allocator()->Deallocate(_ptr);
}
size_type max_size() const noexcept {
return (~size_type(0)) / sizeof(value_type);
}
};
// Tests for allocator equality (always true).
template <class _Ty, class _Other>
inline bool operator==(const StdAllocator<_Ty>&,
const StdAllocator<_Other>&) noexcept {
return true;
}
// Tests for allocator inequality (always false).
template <class _Ty, class _Other>
inline bool operator!=(const StdAllocator<_Ty>&,
const StdAllocator<_Other>&) noexcept {
return false;
}
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_STD_ALLOCATOR_H_
@@ -0,0 +1,41 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_STRING_H_
#define OZZ_OZZ_BASE_CONTAINERS_STRING_H_
#include <string>
#include "ozz/base/containers/std_allocator.h"
namespace ozz {
// Redirects std::basic_string to ozz::string in order to replace std default
// allocator by ozz::StdAllocator.
using string =
std::basic_string<char, std::char_traits<char>, ozz::StdAllocator<char>>;
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_STRING_H_
@@ -0,0 +1,49 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_STRING_ARCHIVE_H_
#define OZZ_OZZ_BASE_CONTAINERS_STRING_ARCHIVE_H_
#include "ozz/base/containers/string.h"
#include "ozz/base/io/archive_traits.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(ozz::string)
template <>
struct Extern<ozz::string> {
static void Save(OArchive& _archive, const ozz::string* _values,
size_t _count);
static void Load(IArchive& _archive, ozz::string* _values, size_t _count,
uint32_t _version);
};
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_STRING_ARCHIVE_H_
@@ -0,0 +1,62 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_UNORDERED_MAP_H_
#define OZZ_OZZ_BASE_CONTAINERS_UNORDERED_MAP_H_
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4702) // warning C4702: unreachable code
#endif // _MSC_VER
#include <unordered_map>
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
#include "ozz/base/containers/std_allocator.h"
namespace ozz {
// Redirects std::unordered_map to ozz::unordered_map in order to replace std
// default allocator by ozz::StdAllocator.
template <class _Key, class _Ty, class _Hash = std::hash<_Key>,
class _KeyEqual = std::equal_to<_Key>,
class _Allocator = ozz::StdAllocator<std::pair<const _Key, _Ty>>>
using unordered_map =
std::unordered_map<_Key, _Ty, _Hash, _KeyEqual, _Allocator>;
// Redirects std::unordered_multimap to ozz::UnorderedMultiMap in order to
// replace std default allocator by ozz::StdAllocator.
template <class _Key, class _Ty, class _Hash = std::hash<_Key>,
class _KeyEqual = std::equal_to<_Key>,
class _Allocator = ozz::StdAllocator<std::pair<const _Key, _Ty>>>
using unordered_multimap =
std::unordered_multimap<_Key, _Ty, _Hash, _KeyEqual, _Allocator>;
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_UNORDERED_MAP_H_
@@ -0,0 +1,52 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_UNORDERED_SET_H_
#define OZZ_OZZ_BASE_CONTAINERS_UNORDERED_SET_H_
#include <unordered_set>
#include "ozz/base/containers/std_allocator.h"
namespace ozz {
// Redirects std::unordered_set to ozz::UnorderedSet in order to replace std
// default allocator by ozz::StdAllocator.
template <class _Key, class _Hash = std::hash<_Key>,
class _KeyEqual = std::equal_to<_Key>,
class _Allocator = ozz::StdAllocator<_Key> >
using unordered_set =
std::unordered_set<_Key, _Hash, _KeyEqual, _Allocator>;
// Redirects std::unordered_multiset to ozz::UnorderedMultiSet in order to
// replace std default allocator by ozz::StdAllocator.
template <class _Key, class _Hash = std::hash<_Key>,
class _KeyEqual = std::equal_to<_Key>,
class _Allocator = ozz::StdAllocator<_Key> >
using unordered_multiset =
std::unordered_multiset<_Key, _Hash, _KeyEqual, _Allocator>;
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_UNORDERED_SET_H_
@@ -0,0 +1,74 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_VECTOR_H_
#define OZZ_OZZ_BASE_CONTAINERS_VECTOR_H_
#include <vector>
#include "ozz/base/containers/std_allocator.h"
namespace ozz {
// Redirects std::vector to ozz::vector in order to replace std default
// allocator by ozz::StdAllocator.
template <class _Ty, class _Allocator = ozz::StdAllocator<_Ty>>
using vector = std::vector<_Ty, _Allocator>;
// Extends std::vector with two functions that gives access to the begin and the
// end of its array of elements.
// Returns the mutable begin of the array of elements, or nullptr if
// vector's empty.
template <class _Ty, class _Allocator>
inline _Ty* array_begin(std::vector<_Ty, _Allocator>& _vector) {
return _vector.data();
}
// Returns the non-mutable begin of the array of elements, or nullptr if
// vector's empty.
template <class _Ty, class _Allocator>
inline const _Ty* array_begin(const std::vector<_Ty, _Allocator>& _vector) {
return _vector.data();
}
// Returns the mutable end of the array of elements, or nullptr if
// vector's empty. Array end is one element past the last element of the
// array, it cannot be dereferenced.
template <class _Ty, class _Allocator>
inline _Ty* array_end(std::vector<_Ty, _Allocator>& _vector) {
return _vector.data() + _vector.size();
}
// Returns the non-mutable end of the array of elements, or nullptr if
// vector's empty. Array end is one element past the last element of the
// array, it cannot be dereferenced.
template <class _Ty, class _Allocator>
inline const _Ty* array_end(const std::vector<_Ty, _Allocator>& _vector) {
return _vector.data() + _vector.size();
}
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_VECTOR_H_
@@ -0,0 +1,72 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_VECTOR_ARCHIVE_H_
#define OZZ_OZZ_BASE_CONTAINERS_VECTOR_ARCHIVE_H_
#include "ozz/base/containers/vector.h"
#include "ozz/base/io/archive.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE_T2(class _Ty, class _Allocator,
std::vector<_Ty, _Allocator>)
template <class _Ty, class _Allocator>
struct Extern<std::vector<_Ty, _Allocator>> {
inline static void Save(OArchive& _archive,
const std::vector<_Ty, _Allocator>* _values,
size_t _count) {
for (size_t i = 0; i < _count; i++) {
const std::vector<_Ty, _Allocator>& vector = _values[i];
const uint32_t size = static_cast<uint32_t>(vector.size());
_archive << size;
if (size > 0) {
_archive << ozz::io::MakeArray(&vector[0], size);
}
}
}
inline static void Load(IArchive& _archive,
std::vector<_Ty, _Allocator>* _values, size_t _count,
uint32_t _version) {
(void)_version;
for (size_t i = 0; i < _count; i++) {
std::vector<_Ty, _Allocator>& vector = _values[i];
uint32_t size;
_archive >> size;
vector.resize(size);
if (size > 0) {
_archive >> ozz::io::MakeArray(&vector[0], size);
}
}
}
};
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_VECTOR_ARCHIVE_H_
+157
View File
@@ -0,0 +1,157 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_ENDIANNESS_H_
#define OZZ_OZZ_BASE_ENDIANNESS_H_
// Declares endianness modes and functions to swap data from a mode to another.
#include <cstddef>
#include "ozz/base/platform.h"
namespace ozz {
// Declares supported endianness.
enum Endianness {
kBigEndian,
kLittleEndian,
};
// Get the native endianness of the targeted processor.
// This function does not rely on a pre-processor definition as no standard
// definition exists. It is rather implemented as a portable runtime function.
inline Endianness GetNativeEndianness() {
const union {
uint16_t s;
uint8_t c[2];
} u = {1}; // Initializes u.s -> then read u.c.
return Endianness(u.c[0]);
}
// Declare the endian swapper struct that is aimed to be specialized (template
// meaning) for every type sizes.
// The swapper provides two functions:
// - void Swap(_Ty* _ty, size_t _count) swaps the array _ty of _count
// elements in-place.
// - _Ty Swap(_Ty _ty) returns a swapped copy of _ty.
// It can be used directly if _Ty is known or through EndianSwap function.
// The default value of template attribute _size enables automatic
// specialization selection.
template <typename _Ty, size_t _size = sizeof(_Ty)>
struct EndianSwapper;
// Internal macro used to swap two bytes.
#define OZZ_BYTE_SWAP(_a, _b) \
do { \
const char temp = _a; \
_a = _b; \
_b = temp; \
} while (0)
// EndianSwapper specialization for 1 byte types.
template <typename _Ty>
struct EndianSwapper<_Ty, 1> {
OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) {
(void)_ty;
(void)_count;
}
OZZ_INLINE static _Ty Swap(_Ty _ty) { return _ty; }
};
// EndianSwapper specialization for 2 bytes types.
template <typename _Ty>
struct EndianSwapper<_Ty, 2> {
OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) {
char* alias = reinterpret_cast<char*>(_ty);
for (size_t i = 0; i < _count * 2; i += 2) {
OZZ_BYTE_SWAP(alias[i + 0], alias[i + 1]);
}
}
OZZ_INLINE static _Ty Swap(_Ty _ty) { // Pass by copy to swap _ty in-place.
char* alias = reinterpret_cast<char*>(&_ty);
OZZ_BYTE_SWAP(alias[0], alias[1]);
return _ty;
}
};
// EndianSwapper specialization for 4 bytes types.
template <typename _Ty>
struct EndianSwapper<_Ty, 4> {
OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) {
char* alias = reinterpret_cast<char*>(_ty);
for (size_t i = 0; i < _count * 4; i += 4) {
OZZ_BYTE_SWAP(alias[i + 0], alias[i + 3]);
OZZ_BYTE_SWAP(alias[i + 1], alias[i + 2]);
}
}
OZZ_INLINE static _Ty Swap(_Ty _ty) { // Pass by copy to swap _ty in-place.
char* alias = reinterpret_cast<char*>(&_ty);
OZZ_BYTE_SWAP(alias[0], alias[3]);
OZZ_BYTE_SWAP(alias[1], alias[2]);
return _ty;
}
};
// EndianSwapper specialization for 8 bytes types.
template <typename _Ty>
struct EndianSwapper<_Ty, 8> {
OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) {
char* alias = reinterpret_cast<char*>(_ty);
for (size_t i = 0; i < _count * 8; i += 8) {
OZZ_BYTE_SWAP(alias[i + 0], alias[i + 7]);
OZZ_BYTE_SWAP(alias[i + 1], alias[i + 6]);
OZZ_BYTE_SWAP(alias[i + 2], alias[i + 5]);
OZZ_BYTE_SWAP(alias[i + 3], alias[i + 4]);
}
}
OZZ_INLINE static _Ty Swap(_Ty _ty) { // Pass by copy to swap _ty in-place.
char* alias = reinterpret_cast<char*>(&_ty);
OZZ_BYTE_SWAP(alias[0], alias[7]);
OZZ_BYTE_SWAP(alias[1], alias[6]);
OZZ_BYTE_SWAP(alias[2], alias[5]);
OZZ_BYTE_SWAP(alias[3], alias[4]);
return _ty;
}
};
// OZZ_BYTE_SWAP is not useful anymore.
#undef OZZ_BYTE_SWAP
// Helper function that swaps _count elements of the array _ty in place.
template <typename _Ty>
OZZ_INLINE void EndianSwap(_Ty* _ty, size_t _count) {
EndianSwapper<_Ty>::Swap(_ty, _count);
}
// Helper function that swaps _ty in place.
template <typename _Ty>
OZZ_INLINE _Ty EndianSwap(_Ty _ty) {
return EndianSwapper<_Ty>::Swap(_ty);
}
} // namespace ozz
#endif // OZZ_OZZ_BASE_ENDIANNESS_H_
+175
View File
@@ -0,0 +1,175 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_GTEST_HELPER_H_
#define OZZ_OZZ_BASE_GTEST_HELPER_H_
#include <sstream>
#include "gtest/gtest.h"
// EXPECT_ASSERTION expands to real death test if assertions are enabled.
// Parameters:
// statement - A statement that a macro such as EXPECT_DEATH would test
// for program termination.
// regex - A regex that a macro such as EXPECT_DEATH would use to test
// the output of statement.
#ifdef NDEBUG
// Expands to nothing if asserts aren't enabled (ie: NDEBUG is defined)
#define EXPECT_ASSERTION(_statement, _regex) \
do { \
} while (void(0), false);
#else // NDEBUG
#ifdef _WIN32
#include <crtdbg.h>
#include <cstdlib>
namespace internal {
// Provides a hook during abort to ensure EXIT_FAILURE is returned.
inline int AbortHook(int, char*, int*) { exit(EXIT_FAILURE); }
} // namespace internal
#define EXPECT_ASSERTION(_statement, _regex) \
do { \
/* During death tests executions:*/ \
/* Disables popping message boxes during crt and stl assertions*/ \
int old_mode = 0; \
(void)old_mode; \
_CRT_REPORT_HOOK old_hook = nullptr; \
(void)old_hook; \
if (testing::internal::GTEST_FLAG(internal_run_death_test).length() > 0) { \
old_mode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); \
old_hook = _CrtSetReportHook(&internal::AbortHook); \
} \
EXPECT_DEATH((void)(_statement), _regex); \
if (testing::internal::GTEST_FLAG(internal_run_death_test).length() > 0) { \
_CrtSetReportMode(_CRT_ASSERT, old_mode); \
(void)_CrtSetReportHook(old_hook); \
} \
\
} while (void(0), 0)
#else // _WIN32
#define EXPECT_ASSERTION(_statement, _regex) EXPECT_DEATH(_statement, _regex)
#endif // _WIN32
#endif // NDEBUG
// EXPECT_EQ_LOG* executes _expression and compares its result with _eq.
// While executing _expression, EXPECT_EQ_LOG redirects _output (ex:
// std::clog) and then expects that the output matched the regular expression
// _re.
#define EXPECT_EQ_LOG(_expression, _eq, _output, _re) \
do { \
internal::RedirectOuputTester tester(_output, _re); \
EXPECT_EQ(_expression, _eq); \
\
} while (void(0), 0)
// There are multiple declinations EXPECT_EQ_LOG*, to match with clog, cerr and
// cout outputs, and verbose level option.
// Specialises EXPECT_EQ_LOG* for verbose clog output type.
#define EXPECT_EQ_LOG_LOGV(_expression, _eq, _re) \
EXPECT_EQ_LOG(_expression, _eq, std::clog, \
ozz::log::kVerbose <= ozz::log::GetLevel() ? _re : nullptr)
// Specialises EXPECT_EQ_LOG* for standard clog output type.
#define EXPECT_EQ_LOG_LOG(_expression, _eq, _re) \
EXPECT_EQ_LOG(_expression, _eq, std::clog, \
ozz::log::kStandard <= ozz::log::GetLevel() ? _re : nullptr)
// Specialises EXPECT_EQ_LOG* for standard cout output type.
#define EXPECT_EQ_LOG_OUT(_expression, _eq, _re) \
EXPECT_EQ_LOG(_expression, _eq, std::cout, \
ozz::log::kStandard <= ozz::log::GetLevel() ? _re : nullptr)
// Specialises EXPECT_EQ_LOG* for standard cerr output type.
#define EXPECT_EQ_LOG_ERR(_expression, _eq, _re) \
EXPECT_EQ_LOG(_expression, _eq, std::cerr, \
ozz::log::kStandard <= ozz::log::GetLevel() ? _re : nullptr)
// EXPECT_EQ_LOG* executes _expression while redirecting _output (ex:
// std::clog) and then expects that the output matched the regular expression
// _re.
#define EXPECT_LOG(_expression, _output, _re) \
do { \
internal::RedirectOuputTester tester(_output, _re); \
(_expression); \
\
} while (void(0), 0)
// There are multiple declinations EXPECT_LOG*, to match with clog, cerr and
// cout outputs, and verbose level option.
// Specialises EXPECT_LOG* for verbose clog output type.
#define EXPECT_LOG_LOGV(_expression, _re) \
EXPECT_LOG(_expression, std::clog, \
ozz::log::kVerbose <= ozz::log::GetLevel() ? _re : nullptr)
// Specialises EXPECT_LOG* for standard clog output type.
#define EXPECT_LOG_LOG(_expression, _re) \
EXPECT_LOG(_expression, std::clog, \
ozz::log::kStandard <= ozz::log::GetLevel() ? _re : nullptr)
// Specialises EXPECT_LOG* for standard cout output type.
#define EXPECT_LOG_OUT(_expression, _re) \
EXPECT_LOG(_expression, std::cout, \
ozz::log::kStandard <= ozz::log::GetLevel() ? _re : nullptr)
// Specialises EXPECT_LOG* for standard cerr output type.
#define EXPECT_LOG_ERR(_expression, _re) \
EXPECT_LOG(_expression, std::cerr, \
ozz::log::kStandard <= ozz::log::GetLevel() ? _re : nullptr)
namespace internal {
class RedirectOuputTester {
public:
// Specify a nullptr _regex to test an empty output
RedirectOuputTester(std::ostream& _ostream, const char* _regex)
: ostream_(_ostream), old_(_ostream.rdbuf()), regex_(_regex) {
// Redirect ostream_ buffer.
ostream_.rdbuf(redirect_.rdbuf());
}
~RedirectOuputTester() {
if (regex_) {
EXPECT_TRUE(::testing::internal::RE::PartialMatch(redirect_.str().c_str(),
regex_));
} else {
EXPECT_EQ(redirect_.str().size(), 0u);
}
// Restore ostream_ buffer.
ostream_.rdbuf(old_);
// finally outputs everything temporary redirected.
ostream_ << redirect_.str();
}
private:
std::ostream& ostream_;
std::streambuf* old_;
const char* regex_;
std::stringstream redirect_;
};
} // namespace internal
#endif // OZZ_OZZ_BASE_GTEST_HELPER_H_
+440
View File
@@ -0,0 +1,440 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_IO_ARCHIVE_H_
#define OZZ_OZZ_BASE_IO_ARCHIVE_H_
// Provides input (IArchive) and output (OArchive) serialization containers.
// Archive are similar to c++ iostream. Data can be saved to a OArchive with
// the << operator, or loaded from a IArchive with the >> operator.
// Primitive data types are simply saved/loaded to/from archives, while struct
// and class are saved/loaded through Save/Load intrusive or non-intrusive
// functions:
// - The intrusive function prototypes are "void Save(ozz::io::OArchive*) const"
// and "void Load(ozz::io::IArchive*)".
// - The non-intrusive functions allow to work on arrays of objects. They must
// be implemented in ozz::io namespace, by specializing the following template
// struct:
// template <typename _Ty>
// struct Extern {
// static void Save(OArchive& _archive, const _Ty* _ty, size_t _count);
// static void Load(IArchive& _archive, _Ty* _ty, size_t _count,
// uint32_t _version);
// };
//
// Arrays of struct/class or primitive types can be saved/loaded with the
// helper function ozz::io::MakeArray() that is then streamed in or out using
// << and >> archive operators: archive << ozz::io::MakeArray(my_array, count);
//
// Versioning can be done using OZZ_IO_TYPE_VERSION macros. Type version
// is saved in the OArchive, and is given back to Load functions to allow to
// manually handle version modifications. Versioning can be disabled using
// OZZ_IO_TYPE_NOT_VERSIONABLE like macros. It can not be re-enabled afterward.
//
// Objects can be assigned a tag using OZZ_IO_TYPE_TAG macros. A tag allows to
// check the type of the next object to read from an archive. An automatic
// assertion check is performed for each object that has a tag. It can also be
// done manually to ensure an archive has the expected content.
//
// Endianness (big-endian or little-endian) can be specified while constructing
// an output archive (ozz::io::OArchive). Input archives automatically handle
// endianness conversion if the native platform endian mode differs from the
// archive one.
//
// IArchive and OArchive expect valid streams as argument, respectively opened
// for reading and writing. Archives do NOT perform error detection while
// reading or writing. All errors are considered programming errors. This leads
// to the following assertions on the user side:
// - When writing: the stream must be big (or grow-able) enough to support the
// data being written.
// - When reading: Stream's tell (position in the stream) must match the object
// being read. To help with this requirement, archives provide a tag mechanism
// that allows to check the tag (ie the type) of the next object to read. Stream
// integrity, like data corruption or file truncation, must also be validated on
// the user side.
#include "ozz/base/endianness.h"
#include "ozz/base/io/stream.h"
#include "ozz/base/platform.h"
#include "ozz/base/span.h"
#include <stdint.h>
#include <cassert>
#include "ozz/base/io/archive_traits.h"
namespace ozz {
namespace io {
namespace internal {
// Defines Tagger helper object struct.
// The boolean template argument is used to automatically select a template
// specialization, whether _Ty has a tag or not.
template <typename _Ty,
bool _HasTag = internal::Tag<const _Ty>::kTagLength != 0>
struct Tagger;
} // namespace internal
// Implements output archive concept used to save/serialize data from a Stream.
// The output endianness mode is set at construction time. It is written to the
// stream to allow the IArchive to perform the required conversion to the native
// endianness mode while reading.
class OArchive {
public:
// Constructs an output archive from the Stream _stream that must be valid
// and opened for writing.
explicit OArchive(Stream* _stream,
Endianness _endianness = GetNativeEndianness());
// Returns true if an endian swap is required while writing.
bool endian_swap() const { return endian_swap_; }
// Saves _size bytes of binary data from _data.
size_t SaveBinary(const void* _data, size_t _size) {
return stream_->Write(_data, _size);
}
// Class type saving.
template <typename _Ty>
void operator<<(const _Ty& _ty) {
internal::Tagger<const _Ty>::Write(*this);
SaveVersion<_Ty>();
Extern<_Ty>::Save(*this, &_ty, 1);
}
// Primitive type saving.
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
void operator<<(_type _v) { \
_type v = endian_swap_ ? EndianSwapper<_type>::Swap(_v) : _v; \
OZZ_IF_DEBUG(size_t size =) stream_->Write(&v, sizeof(v)); \
assert(size == sizeof(v)); \
}
OZZ_IO_PRIMITIVE_TYPE(char)
OZZ_IO_PRIMITIVE_TYPE(int8_t)
OZZ_IO_PRIMITIVE_TYPE(uint8_t)
OZZ_IO_PRIMITIVE_TYPE(int16_t)
OZZ_IO_PRIMITIVE_TYPE(uint16_t)
OZZ_IO_PRIMITIVE_TYPE(int32_t)
OZZ_IO_PRIMITIVE_TYPE(uint32_t)
OZZ_IO_PRIMITIVE_TYPE(int64_t)
OZZ_IO_PRIMITIVE_TYPE(uint64_t)
OZZ_IO_PRIMITIVE_TYPE(bool)
OZZ_IO_PRIMITIVE_TYPE(float)
#undef OZZ_IO_PRIMITIVE_TYPE
// Returns output stream.
Stream* stream() const { return stream_; }
private:
template <typename _Ty>
void SaveVersion() {
// Compilation could fail here if the version is not defined for _Ty, or if
// the .h file containing its definition is not included by the caller of
// this function.
if (void(0), internal::Version<const _Ty>::kValue != 0) {
uint32_t version = internal::Version<const _Ty>::kValue;
*this << version;
}
}
// The output stream.
Stream* stream_;
// Endian swap state, true if a conversion is required while writing.
bool endian_swap_;
};
// Implements input archive concept used to load/de-serialize data to a Stream.
// Endianness conversions are automatically performed according to the Archive
// and the native formats.
class IArchive {
public:
// Constructs an input archive from the Stream _stream that must be opened for
// reading, at the same tell (position in the stream) as when it was passed to
// the OArchive.
explicit IArchive(Stream* _stream);
// Returns true if an endian swap is required while reading.
bool endian_swap() const { return endian_swap_; }
// Loads _size bytes of binary data to _data.
size_t LoadBinary(void* _data, size_t _size) {
return stream_->Read(_data, _size);
}
// Class type loading.
template <typename _Ty>
void operator>>(_Ty& _ty) {
// Only uses tag validation for assertions, as reading cannot fail.
OZZ_IF_DEBUG(bool valid =) internal::Tagger<const _Ty>::Validate(*this);
assert(valid && "Type tag does not match archive content.");
// Loads instance.
uint32_t version = LoadVersion<_Ty>();
Extern<_Ty>::Load(*this, &_ty, 1, version);
}
// Primitive type loading.
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
void operator>>(_type& _v) { \
_type v; \
OZZ_IF_DEBUG(size_t size =) stream_->Read(&v, sizeof(v)); \
assert(size == sizeof(v)); \
_v = endian_swap_ ? EndianSwapper<_type>::Swap(v) : v; \
}
OZZ_IO_PRIMITIVE_TYPE(char)
OZZ_IO_PRIMITIVE_TYPE(int8_t)
OZZ_IO_PRIMITIVE_TYPE(uint8_t)
OZZ_IO_PRIMITIVE_TYPE(int16_t)
OZZ_IO_PRIMITIVE_TYPE(uint16_t)
OZZ_IO_PRIMITIVE_TYPE(int32_t)
OZZ_IO_PRIMITIVE_TYPE(uint32_t)
OZZ_IO_PRIMITIVE_TYPE(int64_t)
OZZ_IO_PRIMITIVE_TYPE(uint64_t)
OZZ_IO_PRIMITIVE_TYPE(bool)
OZZ_IO_PRIMITIVE_TYPE(float)
#undef OZZ_IO_PRIMITIVE_TYPE
template <typename _Ty>
bool TestTag() {
// Only tagged types can be tested. If compilations fails here, it can
// mean the file containing tag declaration is not included.
static_assert(internal::Tag<const _Ty>::kTagLength != 0,
"Tag unknown for type.");
const int tell = stream_->Tell();
bool valid = internal::Tagger<const _Ty>::Validate(*this);
stream_->Seek(tell, Stream::kSet); // Rewinds before the tag test.
return valid;
}
// Returns input stream.
Stream* stream() const { return stream_; }
private:
template <typename _Ty>
uint32_t LoadVersion() {
uint32_t version = 0;
if (void(0), internal::Version<const _Ty>::kValue != 0) {
*this >> version;
}
return version;
}
// The input stream.
Stream* stream_;
// Endian swap state, true if a conversion is required while reading.
bool endian_swap_;
};
// Primitive type are not versionable.
OZZ_IO_TYPE_NOT_VERSIONABLE(char)
OZZ_IO_TYPE_NOT_VERSIONABLE(int8_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(uint8_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(int16_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(uint16_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(int32_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(uint32_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(int64_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(uint64_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(bool)
OZZ_IO_TYPE_NOT_VERSIONABLE(float)
// Default loading and saving external implementation.
template <typename _Ty>
struct Extern {
inline static void Save(OArchive& _archive, const _Ty* _ty, size_t _count) {
for (size_t i = 0; i < _count; ++i) {
_ty[i].Save(_archive);
}
}
inline static void Load(IArchive& _archive, _Ty* _ty, size_t _count,
uint32_t _version) {
for (size_t i = 0; i < _count; ++i) {
_ty[i].Load(_archive, _version);
}
}
};
// Wrapper for dynamic array serialization.
// Must be used through ozz::io::MakeArray.
namespace internal {
template <typename _Ty>
struct Array {
OZZ_INLINE void Save(OArchive& _archive) const {
ozz::io::Extern<_Ty>::Save(_archive, array, count);
}
OZZ_INLINE void Load(IArchive& _archive, uint32_t _version) const {
ozz::io::Extern<_Ty>::Load(_archive, array, count, _version);
}
_Ty* array;
size_t count;
};
// Specialize for const _Ty which can only be saved.
template <typename _Ty>
struct Array<const _Ty> {
OZZ_INLINE void Save(OArchive& _archive) const {
ozz::io::Extern<_Ty>::Save(_archive, array, count);
}
const _Ty* array;
size_t count;
};
// Array copies version from the type it contains.
// Definition of Array of _Ty version: _Ty version.
template <typename _Ty>
struct Version<const Array<_Ty>> {
enum { kValue = Version<const _Ty>::kValue };
};
// Specializes Array Save/Load for primitive types.
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
template <> \
inline void Array<const _type>::Save(OArchive& _archive) const { \
if (_archive.endian_swap()) { \
/* Save element by element as swapping in place the whole buffer is*/ \
/* not possible.*/ \
for (size_t i = 0; i < count; ++i) { \
_archive << array[i]; \
} \
} else { \
OZZ_IF_DEBUG(size_t size =) \
_archive.SaveBinary(array, count * sizeof(_type)); \
assert(size == count * sizeof(_type)); \
} \
} \
\
template <> \
inline void Array<_type>::Save(OArchive& _archive) const { \
if (_archive.endian_swap()) { \
/* Save element by element as swapping in place the whole buffer is*/ \
/* not possible.*/ \
for (size_t i = 0; i < count; ++i) { \
_archive << array[i]; \
} \
} else { \
OZZ_IF_DEBUG(size_t size =) \
_archive.SaveBinary(array, count * sizeof(_type)); \
assert(size == count * sizeof(_type)); \
} \
} \
\
template <> \
inline void Array<_type>::Load(IArchive& _archive, uint32_t /*_version*/) \
const { \
OZZ_IF_DEBUG(size_t size =) \
_archive.LoadBinary(array, count * sizeof(_type)); \
assert(size == count * sizeof(_type)); \
if (_archive.endian_swap()) { /*Can swap in-place.*/ \
EndianSwapper<_type>::Swap(array, count); \
} \
}
OZZ_IO_PRIMITIVE_TYPE(char)
OZZ_IO_PRIMITIVE_TYPE(int8_t)
OZZ_IO_PRIMITIVE_TYPE(uint8_t)
OZZ_IO_PRIMITIVE_TYPE(int16_t)
OZZ_IO_PRIMITIVE_TYPE(uint16_t)
OZZ_IO_PRIMITIVE_TYPE(int32_t)
OZZ_IO_PRIMITIVE_TYPE(uint32_t)
OZZ_IO_PRIMITIVE_TYPE(int64_t)
OZZ_IO_PRIMITIVE_TYPE(uint64_t)
OZZ_IO_PRIMITIVE_TYPE(bool)
OZZ_IO_PRIMITIVE_TYPE(float)
#undef OZZ_IO_PRIMITIVE_TYPE
} // namespace internal
// Utility function that instantiates Array wrapper.
template <typename _Ty>
OZZ_INLINE const internal::Array<_Ty> MakeArray(_Ty* _array, size_t _count) {
const internal::Array<_Ty> array = {_array, _count};
return array;
}
template <typename _Ty>
OZZ_INLINE const internal::Array<const _Ty> MakeArray(const _Ty* _array,
size_t _count) {
const internal::Array<const _Ty> array = {_array, _count};
return array;
}
template <typename _Ty>
OZZ_INLINE const internal::Array<_Ty> MakeArray(span<_Ty> _array) {
const internal::Array<_Ty> array = {_array.data(), _array.size()};
return array;
}
template <typename _Ty>
OZZ_INLINE const internal::Array<const _Ty> MakeArray(span<const _Ty> _array) {
const internal::Array<const _Ty> array = {_array.data(), _array.size()};
return array;
}
template <typename _Ty, size_t _count>
OZZ_INLINE const internal::Array<_Ty> MakeArray(_Ty (&_array)[_count]) {
const internal::Array<_Ty> array = {_array, _count};
return array;
}
template <typename _Ty, size_t _count>
OZZ_INLINE const internal::Array<const _Ty> MakeArray(
const _Ty (&_array)[_count]) {
const internal::Array<const _Ty> array = {_array, _count};
return array;
}
namespace internal {
// Specialization of the Tagger helper for tagged types.
template <typename _Ty>
struct Tagger<_Ty, true> {
static void Write(OArchive& _archive) {
typedef internal::Tag<const _Ty> Tag;
OZZ_IF_DEBUG(size_t size =)
_archive.SaveBinary(Tag::Get(), Tag::kTagLength);
assert(size == Tag::kTagLength);
}
static bool Validate(IArchive& _archive) {
typedef internal::Tag<const _Ty> Tag;
char buf[Tag::kTagLength];
if (Tag::kTagLength != _archive.LoadBinary(buf, Tag::kTagLength)) {
return false;
}
const char* tag = Tag::Get();
size_t i = 0;
for (; i < Tag::kTagLength && buf[i] == tag[i]; ++i) {
}
return i == Tag::kTagLength;
}
};
// Specialization of the Tagger helper for types with no tag.
template <typename _Ty>
struct Tagger<_Ty, false> {
static void Write(OArchive& /*_archive*/) {}
static bool Validate(IArchive& /*_archive*/) { return true; }
};
} // namespace internal
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_IO_ARCHIVE_H_
@@ -0,0 +1,220 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_IO_ARCHIVE_TRAITS_H_
#define OZZ_OZZ_BASE_IO_ARCHIVE_TRAITS_H_
// Provides traits for customizing archive serialization properties: version,
// tag... See archive.h for more details.
#include <stdint.h>
#include <cstddef>
namespace ozz {
namespace io {
// Forward declaration of archive types.
class OArchive;
class IArchive;
// Default loading and saving external declaration.
// Those template implementations aim to be specialized at compilation time by
// non-member Load and save functions. For example the specialization of the
// Save() function for a type Type is:
// void Save(OArchive& _archive, const Extrusive* _test, size_t _count) {
// }
// The Load() function receives the version _version of type _Ty at the time the
// archive was saved.
// This uses polymorphism rather than template specialization to avoid
// including the file that contains the template definition.
//
// This default function call member _Ty::Load/Save function.
template <typename _Ty>
struct Extern;
// Declares the current (compile time) version of _type.
// This macro must be used inside namespace ozz::io.
// Syntax is: OZZ_IO_TYPE_VERSION(46, Foo).
#define OZZ_IO_TYPE_VERSION(_version, _type) \
static_assert(_version > 0, "Version number must be > 0"); \
namespace internal { \
template <> \
struct Version<const _type> { \
enum { kValue = _version }; \
}; \
} // internal
// Declares the current (compile time) version of a template _type.
// This macro must be used inside namespace ozz::io.
// OZZ_IO_TYPE_VERSION_T1(46, typename _T1, Foo<_T1>).
#define OZZ_IO_TYPE_VERSION_T1(_version, _arg0, ...) \
static_assert(_version > 0, "Version number must be > 0"); \
namespace internal { \
template <_arg0> \
struct Version<const __VA_ARGS__> { \
enum { kValue = _version }; \
}; \
} // internal
// Declares the current (compile time) version of a template _type.
// This macro must be used inside namespace ozz::io.
// OZZ_IO_TYPE_VERSION_T2(46, typename _T1, typename _T2, Foo<_T1, _T2>).
#define OZZ_IO_TYPE_VERSION_T2(_version, _arg0, _arg1, ...) \
static_assert(_version > 0, "Version number must be > 0"); \
namespace internal { \
template <_arg0, _arg1> \
struct Version<const __VA_ARGS__> { \
enum { kValue = _version }; \
}; \
\
} // internal
// Declares the current (compile time) version of a template _type.
// This macro must be used inside namespace ozz::io.
// OZZ_IO_TYPE_VERSION_T3(
// 46, typename _T1, typename _T2, typename _T3, Foo<_T1, _T2, _T3>).
#define OZZ_IO_TYPE_VERSION_T3(_version, _arg0, _arg1, _arg2, ...) \
static_assert(_version > 0, "Version number must be > 0"); \
namespace internal { \
template <_arg0, _arg1, _arg2> \
struct Version<const __VA_ARGS__> { \
enum { kValue = _version }; \
}; \
\
} // internal
// Declares the current (compile time) version of a template _type.
// This macro must be used inside namespace ozz::io.
// OZZ_IO_TYPE_VERSION_T4(
// 46, typename _T1, typename _T2, typename _T3, typename _T4,
// Foo<_T1, _T2, _T3, _T4>).
#define OZZ_IO_TYPE_VERSION_T4(_version, _arg0, _arg1, _arg2, _arg3, ...) \
static_assert(_version > 0, "Version number must be > 0"); \
namespace internal { \
template <_arg0, _arg1, _arg2, _arg3> \
struct Version<const __VA_ARGS__> { \
enum { kValue = _version }; \
}; \
} // internal
// Declares that _type is not versionable. Its version number is 0.
// Once a type has been declared not versionable, it cannot be changed without
// braking versioning.
// This macro must be used inside namespace ozz::io.
// Syntax is: OZZ_IO_TYPE_NOT_VERSIONABLE(Foo).
#define OZZ_IO_TYPE_NOT_VERSIONABLE(_type) \
namespace internal { \
template <> \
struct Version<const _type> { \
enum { kValue = 0 }; \
}; \
} // internal
// Declares that a template _type is not versionable. Its version number is 0.
// Once a type has been declared not versionable, it cannot be changed without
// braking versioning.
// This macro must be used inside namespace ozz::io.
// Syntax is:
// OZZ_IO_TYPE_NOT_VERSIONABLE_T1(typename _T1, Foo<_T1>).
#define OZZ_IO_TYPE_NOT_VERSIONABLE_T1(_arg0, ...) \
namespace internal { \
template <_arg0> \
struct Version<const __VA_ARGS__> { \
enum { kValue = 0 }; \
}; \
} // internal
// Decline non-versionable template declaration to 2 template arguments.
// Syntax is:
// OZZ_IO_TYPE_NOT_VERSIONABLE_T2(typename _T1, typename _T2, Foo<_T1, _T2>).
#define OZZ_IO_TYPE_NOT_VERSIONABLE_T2(_arg0, _arg1, ...) \
namespace internal { \
template <_arg0, _arg1> \
struct Version<const __VA_ARGS__> { \
enum { kValue = 0 }; \
}; \
} // internal
// Decline non-versionable template declaration to 3 template arguments.
// Syntax is:
// OZZ_IO_TYPE_NOT_VERSIONABLE_T3(
// typename _T1, typename _T2, typename _T3, Foo<_T1, _T2, _T3>).
#define OZZ_IO_TYPE_NOT_VERSIONABLE_T3(_arg0, _arg1, _arg2, ...) \
namespace internal { \
template <_arg0, _arg1, _arg2> \
struct Version<const __VA_ARGS__> { \
enum { kValue = 0 }; \
}; \
} // internal
// Decline non-versionable template declaration to 4 template arguments.
// Syntax is:
// OZZ_IO_TYPE_NOT_VERSIONABLE_T4(
// typename _T1, typename _T2, typename _T3, typename _T4,
// Foo<_T1, _T2, _T3, _T4>).
#define OZZ_IO_TYPE_NOT_VERSIONABLE_T4(_arg0, _arg1, _arg2, _arg3, ...) \
namespace internal { \
template <_arg0, _arg1, _arg2, _arg3> \
struct Version<const __VA_ARGS__> { \
enum { kValue = 0 }; \
}; \
} // internal
// Declares the tag of a template _type.
// A tag is a c-string that can be used to check the type (through its tag) of
// the next object to be read from an archive. If no tag is defined, then no
// check is performed.
// This macro must be used inside namespace ozz::io.
// OZZ_IO_TYPE_TAG("Foo", Foo).
#define OZZ_IO_TYPE_TAG(_tag, _type) \
namespace internal { \
template <> \
struct Tag<const _type> { \
/* Length includes null terminated character to detect partial */ \
/* tag mapping.*/ \
enum { kTagLength = OZZ_ARRAY_SIZE(_tag) }; \
static const char* Get() { return _tag; } \
}; \
} // internal
namespace internal {
// Definition of version specializable template struct.
// There's no default implementation in order to force user to define it, which
// in turn forces those who want to serialize an object to include the file that
// defines it's version. This helps with detecting issues at compile time.
template <typename _Ty>
struct Version;
// Defines default tag value, which is disabled.
template <typename _Ty>
struct Tag {
enum { kTagLength = 0 };
};
} // namespace internal
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_IO_ARCHIVE_TRAITS_H_
+189
View File
@@ -0,0 +1,189 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_IO_STREAM_H_
#define OZZ_OZZ_BASE_IO_STREAM_H_
// Provides Stream interface used to read/write a memory buffer or a file with
// Crt fread/fwrite/fseek/ftell like functions.
#include "ozz/base/platform.h"
#include <cstddef>
namespace ozz {
namespace io {
// Declares a stream access interface that conforms with CRT FILE API.
// This interface should be used to remap io operations.
class Stream {
public:
// Tests whether a file is opened.
virtual bool opened() const = 0;
// Reads _size bytes of data to _buffer from the stream. _buffer must be big
// enough to store _size bytes. The position indicator of the stream is
// advanced by the total amount of bytes read.
// Returns the number of bytes actually read, which may be less than _size.
virtual size_t Read(void* _buffer, size_t _size) = 0;
// Writes _size bytes of data from _buffer to the stream. The position
// indicator of the stream is advanced by the total number of bytes written.
// Returns the number of bytes actually written, which may be less than _size.
virtual size_t Write(const void* _buffer, size_t _size) = 0;
// Declares seeking origin enumeration.
enum Origin {
kCurrent, // Current position of the stream pointer.
kEnd, // End of stream.
kSet, // Beginning of stream.
};
// Sets the position indicator associated with the stream to a new position
// defined by adding _offset to a reference position specified by _origin.
// Returns a zero value if successful, otherwise returns a non-zero value.
virtual int Seek(int _offset, Origin _origin) = 0;
// Returns the current value of the position indicator of the stream.
// Returns -1 if an error occurs.
virtual int Tell() const = 0;
// Returns the current size of the stream.
virtual size_t Size() const = 0;
protected:
Stream() {}
// Required virtual destructor.
virtual ~Stream() {}
private:
Stream(const Stream&);
void operator=(const Stream&);
};
// Implements Stream of type File.
class File : public Stream {
public:
// Test if a file at path _filename exists.
// Note that this function is costly. If you aim to open the file right after,
// then open it and use File::opened() to test if it's actually existing.
static bool Exist(const char* _filename);
// Open a file at path _filename with mode * _mode, in conformance with fopen
// specifications.
// Use opened() function to test opening result.
File(const char* _filename, const char* _mode);
// Gives _file ownership to the FileStream, which will be in charge of closing
// it. _file must be nullptr or a valid std::FILE pointer.
explicit File(void* _file);
// Close the file if it is opened.
virtual ~File();
// Close the file if it is opened.
void Close();
// See Stream::opened for details.
virtual bool opened() const;
// See Stream::Read for details.
virtual size_t Read(void* _buffer, size_t _size);
// See Stream::Write for details.
virtual size_t Write(const void* _buffer, size_t _size);
// See Stream::Seek for details.
virtual int Seek(int _offset, Origin _origin);
// See Stream::Tell for details.
virtual int Tell() const;
// See Stream::Tell for details.
virtual size_t Size() const;
private:
// The CRT file pointer.
void* file_;
};
// Implements an in-memory Stream. Allows to use a memory buffer as a Stream.
// The opening mode is equivalent to fopen w+b (binary read/write).
class MemoryStream : public Stream {
public:
// Construct an empty memory stream opened in w+b mode.
MemoryStream();
// Closes the stream and deallocates memory buffer.
virtual ~MemoryStream();
// See Stream::opened for details.
virtual bool opened() const;
// See Stream::Read for details.
virtual size_t Read(void* _buffer, size_t _size);
// See Stream::Write for details.
virtual size_t Write(const void* _buffer, size_t _size);
// See Stream::Seek for details.
virtual int Seek(int _offset, Origin _origin);
// See Stream::Tell for details.
virtual int Tell() const;
// See Stream::Tell for details.
virtual size_t Size() const;
private:
// Resizes buffers size to _size bytes. If _size is less than the actual
// buffer size, then it remains unchanged.
// Returns true if the buffer can contains _size bytes.
bool Resize(size_t _size);
// Size of the buffer increment.
static const size_t kBufferSizeIncrement;
// Maximum stream size.
static const size_t kMaxSize;
// Buffer of data.
char* buffer_;
// The size of the buffer, which is greater or equal to the size of the data
// it contains (end_).
size_t alloc_size_;
// The effective size of the data in the buffer.
int end_;
// The cursor position in the buffer of data.
int tell_;
};
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_IO_STREAM_H_
+152
View File
@@ -0,0 +1,152 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_LOG_H_
#define OZZ_OZZ_BASE_LOG_H_
#include <iostream>
// MSVC includes <cstring> from <iostream> but not gcc.
// So it is included here to ensure a portable behavior.
#include <cstring>
// Proposes a logging interface that redirects logs to std::cout, clog and cerr
// output streams. This interface adds a logging level functionality (kSilent,
// kStandard, kVerbose) to the std API, which can be set using
// ozz::log::GetLevel function.
// Usage conforms to std stream usage: ozz::log::Log() << "something to log."...
namespace ozz {
namespace log {
enum Level {
kSilent, // No output at all, even errors are muted.
kStandard, // Default output level.
kVerbose, // Most verbose output level.
};
// Sets the global logging level.
Level SetLevel(Level _level);
// Gets the global logging level.
Level GetLevel();
// Implements logging base class.
// This class is not intended to be used publicly, it is derived by user
// classes LogV, Log, Out, Err...
// Forwards ostream::operator << to a standard ostream or a silent
// ostringstream according to the logging level at construction time.
class Logger {
public:
// Forwards ostream::operator << for any type.
template <typename _T>
std::ostream& operator<<(const _T& _t) {
return stream_ << _t;
}
// Forwards ostream::operator << for modifiers.
std::ostream& operator<<(std::ostream& (*_Pfn)(std::ostream&)) {
return ((*_Pfn)(stream_));
}
// Implicit cast operator.
operator std::ostream&() const { return stream_; }
// Explicit cast function.
std::ostream& stream() const { return stream_; }
protected:
// Specifies the global stream and the output level.
// Logging levels allows to select _stream or a "silent" stream according to
// the current global logging level.
Logger(std::ostream& _stream, Level _level);
// Destructor, deletes the internal "silent" stream.
~Logger();
private:
// Disables copy and assignment.
Logger(const Logger&);
void operator=(Logger&);
// Selected output stream.
std::ostream& stream_;
// Stores whether the stream is local one, in which case it must be deleted
// in the destructor.
bool local_stream_;
};
// Logs verbose output to the standard error stream (std::clog).
// Enabled if logging level is Verbose.
class LogV : public Logger {
public:
LogV();
};
// Logs output to the standard error stream (std::clog).
// Enabled if logging level is not Silent.
class Log : public Logger {
public:
Log();
};
// Logs output to the standard output (std::cout).
// Enabled if logging level is not Silent.
class Out : public Logger {
public:
Out();
};
// Logs error to the standard error stream (std::cerr).
// Enabled if logging level is not Silent.
class Err : public Logger {
public:
Err();
};
// RAII helper that modifies float logging precision, and restores default
// settings when exiting scope.
// User is reponsible for making sure stream still exist upon RAII destruction.
// See std::setprecision() for more details.
class FloatPrecision {
public:
FloatPrecision(const Logger& _logger, int _precision);
~FloatPrecision();
private:
FloatPrecision(FloatPrecision const&);
void operator=(FloatPrecision const&);
// Original precision and format.
const std::streamsize precision_;
const std::ios_base::fmtflags format_;
// Stream on which original precision must be restored.
std::ostream& stream_;
};
} // namespace log
} // namespace ozz
#endif // OZZ_OZZ_BASE_LOG_H_
+84
View File
@@ -0,0 +1,84 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_BOX_H_
#define OZZ_OZZ_BASE_MATHS_BOX_H_
#include <cstddef>
#include "ozz/base/maths/vec_float.h"
namespace ozz {
namespace math {
// Matrix forward declaration.
struct Float4x4;
// Defines an axis aligned box.
struct Box {
// Constructs an invalid box.
Box();
// Constructs a box with the specified _min and _max bounds.
Box(const Float3& _min, const Float3& _max) : min(_min), max(_max) {}
// Constructs the smallest box that contains the _count points _points.
// _stride is the number of bytes between points.
explicit Box(const Float3& _point) : min(_point), max(_point) {}
// Constructs the smallest box that contains the _count points _points.
// _stride is the number of bytes between points, it must be greater or
// equal to sizeof(Float3).
Box(const Float3* _points, size_t _stride, size_t _count);
// Tests whether *this is a valid box.
bool is_valid() const { return min <= max; }
// Tests whether _p is within box bounds.
bool is_inside(const Float3& _p) const { return _p >= min && _p <= max; }
// Box's min and max bounds.
Float3 min;
Float3 max;
};
// Merges two boxes _a and _b.
// Both _a and _b can be invalid.
OZZ_INLINE Box Merge(const Box& _a, const Box& _b) {
if (!_a.is_valid()) {
return _b;
} else if (!_b.is_valid()) {
return _a;
}
return Box(Min(_a.min, _b.min), Max(_a.max, _b.max));
}
// Compute box transformation by a matrix.
Box TransformBox(const Float4x4& _matrix, const Box& _box);
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_BOX_H_
@@ -0,0 +1,463 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_GTEST_MATH_HELPER_H_
#define OZZ_OZZ_BASE_MATHS_GTEST_MATH_HELPER_H_
static const float kFloatNearTolerance = 1e-5f;
static const float kFloatNearEstTolerance = 1e-3f;
// Implements "float near" test as a function. Avoids overloading compiler
// optimizer when too much EXPECT_NEAR are used in a single compilation unit.
inline void ExpectFloatNear(float _a, float _b,
float _tol = kFloatNearTolerance) {
EXPECT_NEAR(_a, _b, _tol);
}
// Implements "int equality" test as a function. Avoids overloading compiler
// optimizer when too much EXPECT_TRUE are used in a single compilation unit.
inline void ExpectIntEq(int _a, int _b) { EXPECT_EQ(_a, _b); }
// Implements "bool equality" test as a function. Avoids overloading compiler
// optimizer when too much EXPECT_TRUE are used in a single compilation unit.
inline void ExpectTrue(bool _b) { EXPECT_TRUE(_b); }
// Macro for testing floats, dedicated to estimated functions with a lower
// precision.
#define EXPECT_FLOAT_EQ_EST(_expected, _x) \
EXPECT_NEAR(_expected, _x, kFloatNearEstTolerance)
// Macro for testing ozz::math::Float4 members with x, y, z, w float values,
// using EXPECT_FLOAT_EQ internally.
#define EXPECT_FLOAT4_EQ(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::Float4 expected(_expected); \
ExpectFloatNear(expected.x, _x); \
ExpectFloatNear(expected.y, _y); \
ExpectFloatNear(expected.z, _z); \
ExpectFloatNear(expected.w, _w); \
\
} while (void(0), 0)
// Macro for testing ozz::math::Float3 members with x, y, z float values,
// using EXPECT_FLOAT_EQ internally.
#define EXPECT_FLOAT3_EQ(_expected, _x, _y, _z) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::Float3 expected(_expected); \
ExpectFloatNear(expected.x, _x); \
ExpectFloatNear(expected.y, _y); \
ExpectFloatNear(expected.z, _z); \
\
} while (void(0), 0)
// Macro for testing ozz::math::Float2 members with x, y float values,
// using EXPECT_NEAR internally.
#define EXPECT_FLOAT2_EQ(_expected, _x, _y) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::Float2 expected(_expected); \
ExpectFloatNear(expected.x, _x); \
ExpectFloatNear(expected.y, _y); \
\
} while (void(0), 0)
// Macro for testing ozz::math::Quaternion members with x, y, z, w float value.
#define EXPECT_QUATERNION_EQ(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::Quaternion expected(_expected); \
ExpectFloatNear(expected.x, _x); \
ExpectFloatNear(expected.y, _y); \
ExpectFloatNear(expected.z, _z); \
ExpectFloatNear(expected.w, _w); \
\
} while (void(0), 0)
#define _IMPL_EXPECT_SIMDFLOAT_EQ_TOL(_expected, _x, _y, _z, _w, _tol) \
\
do { \
union { \
ozz::math::SimdFloat4 ret; \
float af[4]; \
} u = {_expected}; \
ExpectFloatNear(u.af[0], _x, _tol); \
ExpectFloatNear(u.af[1], _y, _tol); \
ExpectFloatNear(u.af[2], _z, _tol); \
ExpectFloatNear(u.af[3], _w, _tol); \
\
} while (void(0), 0)
#define _IMPL_EXPECT_SIMDFLOAT_EQ(_expected, _x, _y, _z, _w) \
_IMPL_EXPECT_SIMDFLOAT_EQ_TOL(_expected, _x, _y, _z, _w, kFloatNearTolerance)
#define _IMPL_EXPECT_SIMDFLOAT_EQ_EST(_expected, _x, _y, _z, _w) \
_IMPL_EXPECT_SIMDFLOAT_EQ_TOL(_expected, _x, _y, _z, _w, \
kFloatNearEstTolerance)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z, w values.
#define EXPECT_SIMDFLOAT_EQ(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT_EQ(_expected, _x, _y, _z, _w); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z, w values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SIMDFLOAT_EQ_EST(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(_expected, _x, _y, _z, _w); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y values with
// a user defined precision.
#define _IMPL_EXPECT_SIMDFLOAT2_EQ_TOL(_expected, _x, _y, _tol) \
\
do { \
union { \
ozz::math::SimdFloat4 ret; \
float af[4]; \
} u = {_expected}; \
ExpectFloatNear(u.af[0], _x, _tol); \
ExpectFloatNear(u.af[1], _y, _tol); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y values.
#define EXPECT_SIMDFLOAT2_EQ(_expected, _x, _y) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT2_EQ_TOL(_expected, _x, _y, kFloatNearTolerance); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SIMDFLOAT2_EQ_EST(_expected, _x, _y) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT2_EQ_TOL(_expected, _x, _y, kFloatNearEstTolerance); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z values.
// Dedicated to estimated functions with a user defined precision.
#define EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, _tol) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, _tol); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z values with
// a user defined precision.
#define _IMPL_EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, _tol) \
\
do { \
union { \
ozz::math::SimdFloat4 ret; \
float af[4]; \
} u = {_expected}; \
ExpectFloatNear(u.af[0], _x, _tol); \
ExpectFloatNear(u.af[1], _y, _tol); \
ExpectFloatNear(u.af[2], _z, _tol); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z values.
#define EXPECT_SIMDFLOAT3_EQ(_expected, _x, _y, _z) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, \
kFloatNearTolerance); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SIMDFLOAT3_EQ_EST(_expected, _x, _y, _z) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, \
kFloatNearEstTolerance); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z values.
// Dedicated to estimated functions with a user defined precision.
#define EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, _tol) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, _tol); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdInt members with x, y, z, w values.
#define EXPECT_SIMDINT_EQ(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
union { \
ozz::math::SimdInt4 ret; \
int ai[4]; \
} u = {_expected}; \
ExpectIntEq(u.ai[0], static_cast<int>(_x)); \
ExpectIntEq(u.ai[1], static_cast<int>(_y)); \
ExpectIntEq(u.ai[2], static_cast<int>(_z)); \
ExpectIntEq(u.ai[3], static_cast<int>(_w)); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat4 members with x, y, z, w float values.
#define EXPECT_FLOAT4x4_EQ(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, _y3, \
_z0, _z1, _z2, _z3, _w0, _w1, _w2, _w3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::Float4x4 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[0], _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[1], _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[2], _z0, _z1, _z2, _z3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[3], _w0, _w1, _w2, _w3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdQuaternion members with x, y, z, w
// values.
#define EXPECT_SIMDQUATERNION_EQ(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT_EQ(_expected.xyzw, _x, _y, _z, _w); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdQuaternion members with x, y, z, w
// values.
#define EXPECT_SIMDQUATERNION_EQ_EST(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(_expected.xyzw, _x, _y, _z, _w); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdQuaternion members with x, y, z, w
// values.
#define EXPECT_SIMDQUATERNION_EQ_TOL(_expected, _x, _y, _z, _w, _tol) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT_EQ_TOL(_expected.xyzw, _x, _y, _z, _w, _tol); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat4 members with x, y, z, w float values.
#define EXPECT_SOAFLOAT4_EQ(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, _y3, \
_z0, _z1, _z2, _z3, _w0, _w1, _w2, _w3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat4 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.y, _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.z, _z0, _z1, _z2, _z3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.w, _w0, _w1, _w2, _w3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat4 members with x, y, z, w float values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SOAFLOAT4_EQ_EST(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, \
_y3, _z0, _z1, _z2, _z3, _w0, _w1, _w2, _w3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat4 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.y, _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.z, _z0, _z1, _z2, _z3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.w, _w0, _w1, _w2, _w3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat3 members with x, y, z float values.
#define EXPECT_SOAFLOAT3_EQ(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, _y3, \
_z0, _z1, _z2, _z3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat3 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.y, _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.z, _z0, _z1, _z2, _z3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat3 members with x, y, z float values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SOAFLOAT3_EQ_EST(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, \
_y3, _z0, _z1, _z2, _z3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat3 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.y, _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.z, _z0, _z1, _z2, _z3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat2 members with x, y float values.
#define EXPECT_SOAFLOAT2_EQ(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, _y3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat2 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.y, _y0, _y1, _y2, _y3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat2 members with x, y float values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SOAFLOAT2_EQ_EST(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, \
_y3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat2 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.y, _y0, _y1, _y2, _y3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat2 members with x, y float values.
#define EXPECT_SOAFLOAT1_EQ(_expected, _x0, _x1, _x2, _x3) \
_IMPL_EXPECT_SIMDFLOAT_EQ(_expected, _x0, _x1, _x2, _x3);
// Macro for testing ozz::math::SoaFloat2 members with x, y float values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SOAFLOAT1_EQ_EST(_expected, _x0, _x1, _x2, _x3) \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(_expected, _x0, _x1, _x2, _x3);
// Macro for testing ozz::math::SoaQuaternion members with x, y, z, w float
// values.
#define EXPECT_SOAQUATERNION_EQ(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, \
_y3, _z0, _z1, _z2, _z3, _w0, _w1, _w2, _w3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaQuaternion expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.y, _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.z, _z0, _z1, _z2, _z3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.w, _w0, _w1, _w2, _w3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaQuaternion members with x, y, z, w float
// values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SOAQUATERNION_EQ_EST(_expected, _x0, _x1, _x2, _x3, _y0, _y1, \
_y2, _y3, _z0, _z1, _z2, _z3, _w0, _w1, \
_w2, _w3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaQuaternion expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.y, _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.z, _z0, _z1, _z2, _z3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.w, _w0, _w1, _w2, _w3); \
\
} while (void(0), 0)
#define EXPECT_SOAFLOAT4x4_EQ( \
_expected, col0xx, col0xy, col0xz, col0xw, col0yx, col0yy, col0yz, col0yw, \
col0zx, col0zy, col0zz, col0zw, col0wx, col0wy, col0wz, col0ww, col1xx, \
col1xy, col1xz, col1xw, col1yx, col1yy, col1yz, col1yw, col1zx, col1zy, \
col1zz, col1zw, col1wx, col1wy, col1wz, col1ww, col2xx, col2xy, col2xz, \
col2xw, col2yx, col2yy, col2yz, col2yw, col2zx, col2zy, col2zz, col2zw, \
col2wx, col2wy, col2wz, col2ww, col3xx, col3xy, col3xz, col3xw, col3yx, \
col3yy, col3yz, col3yw, col3zx, col3zy, col3zz, col3zw, col3wx, col3wy, \
col3wz, col3ww) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat4x4 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[0].x, col0xx, col0xy, col0xz, \
col0xw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[0].y, col0yx, col0yy, col0yz, \
col0yw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[0].z, col0zx, col0zy, col0zz, \
col0zw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[0].w, col0wx, col0wy, col0wz, \
col0ww); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[1].x, col1xx, col1xy, col1xz, \
col1xw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[1].y, col1yx, col1yy, col1yz, \
col1yw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[1].z, col1zx, col1zy, col1zz, \
col1zw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[1].w, col1wx, col1wy, col1wz, \
col1ww); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[2].x, col2xx, col2xy, col2xz, \
col2xw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[2].y, col2yx, col2yy, col2yz, \
col2yw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[2].z, col2zx, col2zy, col2zz, \
col2zw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[2].w, col2wx, col2wy, col2wz, \
col2ww); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[3].x, col3xx, col3xy, col3xz, \
col3xw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[3].y, col3yx, col3yy, col3yz, \
col3yw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[3].z, col3zx, col3zy, col3zz, \
col3zw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[3].w, col3wx, col3wy, col3wz, \
col3ww); \
\
} while (void(0), 0)
#endif // OZZ_OZZ_BASE_MATHS_GTEST_MATH_HELPER_H_
@@ -0,0 +1,159 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_INTERNAL_SIMD_MATH_CONFIG_H_
#define OZZ_OZZ_BASE_MATHS_INTERNAL_SIMD_MATH_CONFIG_H_
#include "ozz/base/platform.h"
// Avoid SIMD instruction detection if reference (aka scalar) implementation is
// forced.
#if !defined(OZZ_BUILD_SIMD_REF)
// Try to match a SSE2+ version.
#if defined(__AVX2__) || defined(OZZ_SIMD_AVX2)
#include <immintrin.h>
#define OZZ_SIMD_AVX2
#define OZZ_SIMD_AVX // avx is available if avx2 is.
#endif
#if defined(__FMA__) || defined(OZZ_SIMD_FMA)
#include <immintrin.h>
#define OZZ_SIMD_FMA
#endif
#if defined(__AVX__) || defined(OZZ_SIMD_AVX)
#include <immintrin.h>
#define OZZ_SIMD_AVX
#define OZZ_SIMD_SSE4_2 // SSE4.2 is available if avx is.
#endif
#if defined(__SSE4_2__) || defined(OZZ_SIMD_SSE4_2)
#include <nmmintrin.h>
#define OZZ_SIMD_SSE4_2
#define OZZ_SIMD_SSE4_1 // SSE4.1 is available if SSE4.2 is.
#endif
#if defined(__SSE4_1__) || defined(OZZ_SIMD_SSE4_1)
#include <smmintrin.h>
#define OZZ_SIMD_SSE4_1
#define OZZ_SIMD_SSSE3 // SSSE3 is available if SSE4.1 is.
#endif
#if defined(__SSSE3__) || defined(OZZ_SIMD_SSSE3)
#include <tmmintrin.h>
#define OZZ_SIMD_SSSE3
#define OZZ_SIMD_SSE3 // SSE3 is available if SSSE3 is.
#endif
#if defined(__SSE3__) || defined(OZZ_SIMD_SSE3)
#include <pmmintrin.h>
#define OZZ_SIMD_SSE3
#define OZZ_SIMD_SSE2 // SSE2 is available if SSE3 is.
#endif
// x64/amd64 have SSE2 instructions
// _M_IX86_FP is 2 if /arch:SSE2, /arch:AVX or /arch:AVX2 was used.
#if defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || \
(_M_IX86_FP >= 2) || defined(OZZ_SIMD_SSE2)
#include <emmintrin.h>
#define OZZ_SIMD_SSE2
#define OZZ_SIMD_SSEx // OZZ_SIMD_SSEx is the generic flag for SSE support
#endif
// End of SIMD instruction detection
#endif // !OZZ_BUILD_SIMD_REF
// SEE* intrinsics available
#if defined(OZZ_SIMD_SSEx)
namespace ozz {
namespace math {
// Vector of four floating point values.
typedef __m128 SimdFloat4;
// Argument type for Float4.
typedef const __m128 _SimdFloat4;
// Vector of four integer values.
typedef __m128i SimdInt4;
// Argument type for Int4.
typedef const __m128i _SimdInt4;
} // namespace math
} // namespace ozz
#else // No builtin simd available
// No simd instruction set detected, switch back to reference implementation.
// OZZ_SIMD_REF is the generic flag for SIMD reference implementation.
#define OZZ_SIMD_REF
// Declares reference simd float and integer vectors outside of ozz::math, in
// order to match non-reference implementation details.
// Vector of four floating point values.
struct SimdFloat4Def {
alignas(16) float x;
float y;
float z;
float w;
};
// Vector of four integer values.
struct SimdInt4Def {
alignas(16) int x;
int y;
int z;
int w;
};
namespace ozz {
namespace math {
// Vector of four floating point values.
typedef SimdFloat4Def SimdFloat4;
// Argument type for SimdFloat4
typedef const SimdFloat4& _SimdFloat4;
// Vector of four integer values.
typedef SimdInt4Def SimdInt4;
// Argument type for SimdInt4.
typedef const SimdInt4& _SimdInt4;
} // namespace math
} // namespace ozz
#endif // OZZ_SIMD_x
// Native SIMD operator already exist on some compilers, so they have to be disable from ozz implementation
#if !defined(OZZ_SIMD_REF) && (defined(__GNUC__) || defined(__llvm__))
#define OZZ_DISABLE_SSE_NATIVE_OPERATORS
#endif
#endif // OZZ_OZZ_BASE_MATHS_INTERNAL_SIMD_MATH_CONFIG_H_
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,118 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_MATH_ARCHIVE_H_
#define OZZ_OZZ_BASE_MATHS_MATH_ARCHIVE_H_
#include "ozz/base/io/archive_traits.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
struct Float2;
struct Float3;
struct Float4;
struct Quaternion;
struct Transform;
struct Box;
struct RectFloat;
struct RectInt;
} // namespace math
namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float2)
template <>
struct Extern<math::Float2> {
static void Save(OArchive& _archive, const math::Float2* _values,
size_t _count);
static void Load(IArchive& _archive, math::Float2* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float3)
template <>
struct Extern<math::Float3> {
static void Save(OArchive& _archive, const math::Float3* _values,
size_t _count);
static void Load(IArchive& _archive, math::Float3* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float4)
template <>
struct Extern<math::Float4> {
static void Save(OArchive& _archive, const math::Float4* _values,
size_t _count);
static void Load(IArchive& _archive, math::Float4* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Quaternion)
template <>
struct Extern<math::Quaternion> {
static void Save(OArchive& _archive, const math::Quaternion* _values,
size_t _count);
static void Load(IArchive& _archive, math::Quaternion* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Transform)
template <>
struct Extern<math::Transform> {
static void Save(OArchive& _archive, const math::Transform* _values,
size_t _count);
static void Load(IArchive& _archive, math::Transform* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Box)
template <>
struct Extern<math::Box> {
static void Save(OArchive& _archive, const math::Box* _values, size_t _count);
static void Load(IArchive& _archive, math::Box* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::RectFloat)
template <>
struct Extern<math::RectFloat> {
static void Save(OArchive& _archive, const math::RectFloat* _values,
size_t _count);
static void Load(IArchive& _archive, math::RectFloat* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::RectInt)
template <>
struct Extern<math::RectInt> {
static void Save(OArchive& _archive, const math::RectInt* _values,
size_t _count);
static void Load(IArchive& _archive, math::RectInt* _values, size_t _count,
uint32_t _version);
};
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_MATH_ARCHIVE_H_
@@ -0,0 +1,61 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_MATH_CONSTANT_H_
#define OZZ_OZZ_BASE_MATHS_MATH_CONSTANT_H_
#ifndef INCLUDE_OZZ_MATH_CONSTANT_H_
#define INCLUDE_OZZ_MATH_CONSTANT_H_
namespace ozz {
namespace math {
// Defines math trigonometric constants.
static const float k2Pi = 6.283185307179586476925286766559f;
static const float kPi = 3.1415926535897932384626433832795f;
static const float kPi_2 = 1.5707963267948966192313216916398f;
static const float kPi_4 = .78539816339744830961566084581988f;
static const float kSqrt3 = 1.7320508075688772935274463415059f;
static const float kSqrt3_2 = 0.86602540378443864676372317075294f;
static const float kSqrt2 = 1.4142135623730950488016887242097f;
static const float kSqrt2_2 = 0.70710678118654752440084436210485f;
// Angle unit conversion constants.
static const float kDegreeToRadian = kPi / 180.f;
static const float kRadianToDegree = 180.f / kPi;
// Defines the square normalization tolerance value.
static const float kNormalizationToleranceSq = 1e-6f;
static const float kNormalizationToleranceEstSq = 2e-3f;
// Defines the square orthogonalisation tolerance value.
static const float kOrthogonalisationToleranceSq = 1e-16f;
} // namespace math
} // namespace ozz
#endif // INCLUDE_OZZ_MATH_CONSTANT_H_
#endif // OZZ_OZZ_BASE_MATHS_MATH_CONSTANT_H_
+125
View File
@@ -0,0 +1,125 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_MATH_EX_H_
#define OZZ_OZZ_BASE_MATHS_MATH_EX_H_
#include <cassert>
#include <cmath>
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
// Returns the linear interpolation of _a and _b with coefficient _f.
// _f is not limited to range [0,1].
OZZ_INLINE float Lerp(float _a, float _b, float _f) {
return (_b - _a) * _f + _a;
}
// Returns the minimum of _a and _b. Comparison's based on operator <.
template <typename _Ty>
OZZ_INLINE _Ty Min(_Ty _a, _Ty _b) {
return (_a < _b) ? _a : _b;
}
// Returns the maximum of _a and _b. Comparison's based on operator <.
template <typename _Ty>
OZZ_INLINE _Ty Max(_Ty _a, _Ty _b) {
return (_b < _a) ? _a : _b;
}
// Clamps _x between _a and _b. Comparison's based on operator <.
// Result is unknown if _a is not less or equal to _b.
template <typename _Ty>
OZZ_INLINE _Ty Clamp(_Ty _a, _Ty _x, _Ty _b) {
const _Ty min = _x < _b ? _x : _b;
return min < _a ? _a : min;
}
// Implements int selection, avoiding branching.
OZZ_INLINE int Select(bool _b, int _true, int _false) {
return _false ^ (-static_cast<int>(_b) & (_true ^ _false));
}
// Implements float selection, avoiding branching.
OZZ_INLINE float Select(bool _b, float _true, float _false) {
union {
float f;
int32_t i;
} t = {_true};
union {
float f;
int32_t i;
} f = {_false};
union {
int32_t i;
float f;
} r = {f.i ^ (-static_cast<int32_t>(_b) & (t.i ^ f.i))};
return r.f;
}
// Implements pointer selection, avoiding branching.
template <typename _Ty>
OZZ_INLINE _Ty* Select(bool _b, _Ty* _true, _Ty* _false) {
union {
_Ty* p;
intptr_t i;
} t = {_true};
union {
_Ty* p;
intptr_t i;
} f = {_false};
union {
intptr_t i;
_Ty* p;
} r = {f.i ^ (-static_cast<intptr_t>(_b) & (t.i ^ f.i))};
return r.p;
}
// Implements const pointer selection, avoiding branching.
template <typename _Ty>
OZZ_INLINE const _Ty* Select(bool _b, const _Ty* _true, const _Ty* _false) {
union {
const _Ty* p;
intptr_t i;
} t = {_true};
union {
const _Ty* p;
intptr_t i;
} f = {_false};
union {
intptr_t i;
const _Ty* p;
} r = {f.i ^ (-static_cast<intptr_t>(_b) & (t.i ^ f.i))};
return r.p;
}
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_MATH_EX_H_
@@ -0,0 +1,370 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_QUATERNION_H_
#define OZZ_OZZ_BASE_MATHS_QUATERNION_H_
#include <cassert>
#include "ozz/base/maths/math_constant.h"
#include "ozz/base/maths/math_ex.h"
#include "ozz/base/maths/vec_float.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
struct Quaternion {
float x, y, z, w;
// Constructs an uninitialized quaternion.
OZZ_INLINE Quaternion() {}
// Constructs a quaternion from 4 floating point values.
OZZ_INLINE Quaternion(float _x, float _y, float _z, float _w)
: x(_x), y(_y), z(_z), w(_w) {}
// Returns a normalized quaternion initialized from an axis angle
// representation.
// Assumes the axis part (x, y, z) of _axis_angle is normalized.
// _angle.x is the angle in radian.
static OZZ_INLINE Quaternion FromAxisAngle(const Float3& _axis, float _angle);
// Returns a normalized quaternion initialized from an axis and angle cosine
// representation.
// Assumes the axis part (x, y, z) of _axis_angle is normalized.
// _angle.x is the angle cosine in radian, it must be within [-1,1] range.
static OZZ_INLINE Quaternion FromAxisCosAngle(const Float3& _axis,
float _cos);
// Returns a normalized quaternion initialized from an Euler representation.
// Euler angles are ordered Heading, Elevation and Bank, or Yaw, Pitch and
// Roll.
static OZZ_INLINE Quaternion FromEuler(float _yaw, float _pitch,
float _roll);
// Returns the quaternion that will rotate vector _from into vector _to,
// around their plan perpendicular axis.The input vectors don't need to be
// normalized, they can be null as well.
static OZZ_INLINE Quaternion FromVectors(const Float3& _from,
const Float3& _to);
// Returns the quaternion that will rotate vector _from into vector _to,
// around their plan perpendicular axis. The input vectors must be normalized.
static OZZ_INLINE Quaternion FromUnitVectors(const Float3& _from,
const Float3& _to);
// Returns the identity quaternion.
static OZZ_INLINE Quaternion identity() {
return Quaternion(0.f, 0.f, 0.f, 1.f);
}
};
// Returns true if each element of a is equal to each element of _b.
OZZ_INLINE bool operator==(const Quaternion& _a, const Quaternion& _b) {
return _a.x == _b.x && _a.y == _b.y && _a.z == _b.z && _a.w == _b.w;
}
// Returns true if one element of a differs from one element of _b.
OZZ_INLINE bool operator!=(const Quaternion& _a, const Quaternion& _b) {
return _a.x != _b.x || _a.y != _b.y || _a.z != _b.z || _a.w != _b.w;
}
// Returns the conjugate of _q. This is the same as the inverse if _q is
// normalized. Otherwise the magnitude of the inverse is 1.f/|_q|.
OZZ_INLINE Quaternion Conjugate(const Quaternion& _q) {
return Quaternion(-_q.x, -_q.y, -_q.z, _q.w);
}
// Returns the addition of _a and _b.
OZZ_INLINE Quaternion operator+(const Quaternion& _a, const Quaternion& _b) {
return Quaternion(_a.x + _b.x, _a.y + _b.y, _a.z + _b.z, _a.w + _b.w);
}
// Returns the multiplication of _q and a scalar _f.
OZZ_INLINE Quaternion operator*(const Quaternion& _q, float _f) {
return Quaternion(_q.x * _f, _q.y * _f, _q.z * _f, _q.w * _f);
}
// Returns the multiplication of _a and _b. If both _a and _b are normalized,
// then the result is normalized.
OZZ_INLINE Quaternion operator*(const Quaternion& _a, const Quaternion& _b) {
return Quaternion(_a.w * _b.x + _a.x * _b.w + _a.y * _b.z - _a.z * _b.y,
_a.w * _b.y + _a.y * _b.w + _a.z * _b.x - _a.x * _b.z,
_a.w * _b.z + _a.z * _b.w + _a.x * _b.y - _a.y * _b.x,
_a.w * _b.w - _a.x * _b.x - _a.y * _b.y - _a.z * _b.z);
}
// Returns the negate of _q. This represent the same rotation as q.
OZZ_INLINE Quaternion operator-(const Quaternion& _q) {
return Quaternion(-_q.x, -_q.y, -_q.z, -_q.w);
}
// Returns true if the angle between _a and _b is less than _tolerance.
OZZ_INLINE bool Compare(const math::Quaternion& _a, const math::Quaternion& _b,
float _cos_half_tolerance) {
// Computes w component of a-1 * b.
const float cos_half_angle =
_a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
return std::abs(cos_half_angle) >= _cos_half_tolerance;
}
// Returns true if _q is a normalized quaternion.
OZZ_INLINE bool IsNormalized(const Quaternion& _q) {
const float sq_len = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
return std::abs(sq_len - 1.f) < kNormalizationToleranceSq;
}
// Returns the normalized quaternion _q.
OZZ_INLINE Quaternion Normalize(const Quaternion& _q) {
const float sq_len = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
assert(sq_len != 0.f && "_q is not normalizable");
const float inv_len = 1.f / std::sqrt(sq_len);
return Quaternion(_q.x * inv_len, _q.y * inv_len, _q.z * inv_len,
_q.w * inv_len);
}
// Returns the normalized quaternion _q if the norm of _q is not 0.
// Otherwise returns _safer.
OZZ_INLINE Quaternion NormalizeSafe(const Quaternion& _q,
const Quaternion& _safer) {
assert(IsNormalized(_safer) && "_safer is not normalized");
const float sq_len = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
if (sq_len == 0) {
return _safer;
}
const float inv_len = 1.f / std::sqrt(sq_len);
return Quaternion(_q.x * inv_len, _q.y * inv_len, _q.z * inv_len,
_q.w * inv_len);
}
OZZ_INLINE Quaternion Quaternion::FromAxisAngle(const Float3& _axis,
float _angle) {
assert(IsNormalized(_axis) && "axis is not normalized.");
const float half_angle = _angle * .5f;
const float half_sin = std::sin(half_angle);
const float half_cos = std::cos(half_angle);
return Quaternion(_axis.x * half_sin, _axis.y * half_sin, _axis.z * half_sin,
half_cos);
}
OZZ_INLINE Quaternion Quaternion::FromAxisCosAngle(const Float3& _axis,
float _cos) {
assert(IsNormalized(_axis) && "axis is not normalized.");
assert(_cos >= -1.f && _cos <= 1.f && "cos is not in [-1,1] range.");
const float half_cos2 = (1.f + _cos) * 0.5f;
const float half_sin = std::sqrt(1.f - half_cos2);
return Quaternion(_axis.x * half_sin, _axis.y * half_sin, _axis.z * half_sin,
std::sqrt(half_cos2));
}
// Returns to an axis angle representation of quaternion _q.
// Assumes quaternion _q is normalized.
OZZ_INLINE Float4 ToAxisAngle(const Quaternion& _q) {
assert(IsNormalized(_q));
const float clamped_w = Clamp(-1.f, _q.w, 1.f);
const float angle = 2.f * std::acos(clamped_w);
const float s = std::sqrt(1.f - clamped_w * clamped_w);
// Assuming quaternion normalized then s always positive.
if (s < .001f) { // Tests to avoid divide by zero.
// If s close to zero then direction of axis is not important.
return Float4(1.f, 0.f, 0.f, angle);
} else {
// Normalize axis
const float inv_s = 1.f / s;
return Float4(_q.x * inv_s, _q.y * inv_s, _q.z * inv_s, angle);
}
}
OZZ_INLINE Quaternion Quaternion::FromEuler(float _yaw, float _pitch,
float _roll) {
const float half_yaw = _yaw * .5f;
const float c1 = std::cos(half_yaw);
const float s1 = std::sin(half_yaw);
const float half_pitch = _pitch * .5f;
const float c2 = std::cos(half_pitch);
const float s2 = std::sin(half_pitch);
const float half_roll = _roll * .5f;
const float c3 = std::cos(half_roll);
const float s3 = std::sin(half_roll);
const float c1c2 = c1 * c2;
const float s1s2 = s1 * s2;
return Quaternion(c1c2 * s3 + s1s2 * c3, s1 * c2 * c3 + c1 * s2 * s3,
c1 * s2 * c3 - s1 * c2 * s3, c1c2 * c3 - s1s2 * s3);
}
// Returns to an Euler representation of quaternion _q.
// Quaternion _q does not require to be normalized.
OZZ_INLINE Float3 ToEuler(const Quaternion& _q) {
const float sqw = _q.w * _q.w;
const float sqx = _q.x * _q.x;
const float sqy = _q.y * _q.y;
const float sqz = _q.z * _q.z;
// If normalized is one, otherwise is correction factor.
const float unit = sqx + sqy + sqz + sqw;
const float test = _q.x * _q.y + _q.z * _q.w;
Float3 euler;
if (test > .499f * unit) { // Singularity at north pole
euler.x = 2.f * std::atan2(_q.x, _q.w);
euler.y = ozz::math::kPi_2;
euler.z = 0;
} else if (test < -.499f * unit) { // Singularity at south pole
euler.x = -2 * std::atan2(_q.x, _q.w);
euler.y = -kPi_2;
euler.z = 0;
} else {
euler.x = std::atan2(2.f * _q.y * _q.w - 2.f * _q.x * _q.z,
sqx - sqy - sqz + sqw);
euler.y = std::asin(2.f * test / unit);
euler.z = std::atan2(2.f * _q.x * _q.w - 2.f * _q.y * _q.z,
-sqx + sqy - sqz + sqw);
}
return euler;
}
OZZ_INLINE Quaternion Quaternion::FromVectors(const Float3& _from,
const Float3& _to) {
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
const float norm_from_norm_to = std::sqrt(LengthSqr(_from) * LengthSqr(_to));
if (norm_from_norm_to < 1.e-5f) {
return Quaternion::identity();
}
const float real_part = norm_from_norm_to + Dot(_from, _to);
Quaternion quat;
if (real_part < 1.e-6f * norm_from_norm_to) {
// If _from and _to are exactly opposite, rotate 180 degrees around an
// arbitrary orthogonal axis. Axis normalization can happen later, when we
// normalize the quaternion.
quat = std::abs(_from.x) > std::abs(_from.z)
? Quaternion(-_from.y, _from.x, 0.f, 0.f)
: Quaternion(0.f, -_from.z, _from.y, 0.f);
} else {
const Float3 cross = Cross(_from, _to);
quat = Quaternion(cross.x, cross.y, cross.z, real_part);
}
return Normalize(quat);
}
OZZ_INLINE Quaternion Quaternion::FromUnitVectors(const Float3& _from,
const Float3& _to) {
assert(IsNormalized(_from) && IsNormalized(_to) &&
"Input vectors must be normalized.");
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
const float real_part = 1.f + Dot(_from, _to);
if (real_part < 1.e-6f) {
// If _from and _to are exactly opposite, rotate 180 degrees around an
// arbitrary orthogonal axis.
// Normalisation isn't needed, as from is already.
return std::abs(_from.x) > std::abs(_from.z)
? Quaternion(-_from.y, _from.x, 0.f, 0.f)
: Quaternion(0.f, -_from.z, _from.y, 0.f);
} else {
const Float3 cross = Cross(_from, _to);
return Normalize(Quaternion(cross.x, cross.y, cross.z, real_part));
}
}
// Returns the dot product of _a and _b.
OZZ_INLINE float Dot(const Quaternion& _a, const Quaternion& _b) {
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
}
// Returns the linear interpolation of quaternion _a and _b with coefficient
// _f.
OZZ_INLINE Quaternion Lerp(const Quaternion& _a, const Quaternion& _b,
float _f) {
return Quaternion((_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w);
}
// Returns the linear interpolation of quaternion _a and _b with coefficient
// _f. _a and _n must be from the same hemisphere (aka dot(_a, _b) >= 0).
OZZ_INLINE Quaternion NLerp(const Quaternion& _a, const Quaternion& _b,
float _f) {
const Float4 lerp((_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w);
const float sq_len =
lerp.x * lerp.x + lerp.y * lerp.y + lerp.z * lerp.z + lerp.w * lerp.w;
const float inv_len = 1.f / std::sqrt(sq_len);
return Quaternion(lerp.x * inv_len, lerp.y * inv_len, lerp.z * inv_len,
lerp.w * inv_len);
}
// Returns the spherical interpolation of quaternion _a and _b with
// coefficient _f.
OZZ_INLINE Quaternion SLerp(const Quaternion& _a, const Quaternion& _b,
float _f) {
assert(IsNormalized(_a));
assert(IsNormalized(_b));
// Calculate angle between them.
float cos_half_theta = _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
// If _a=_b or _a=-_b then theta = 0 and we can return _a.
if (std::abs(cos_half_theta) >= .999f) {
return _a;
}
// Calculate temporary values.
const float half_theta = std::acos(cos_half_theta);
const float sin_half_theta = std::sqrt(1.f - cos_half_theta * cos_half_theta);
// If theta = pi then result is not fully defined, we could rotate around
// any axis normal to _a or _b.
if (sin_half_theta < .001f) {
return Quaternion((_a.x + _b.x) * .5f, (_a.y + _b.y) * .5f,
(_a.z + _b.z) * .5f, (_a.w + _b.w) * .5f);
}
const float ratio_a = std::sin((1.f - _f) * half_theta) / sin_half_theta;
const float ratio_b = std::sin(_f * half_theta) / sin_half_theta;
// Calculate Quaternion.
return Quaternion(
ratio_a * _a.x + ratio_b * _b.x, ratio_a * _a.y + ratio_b * _b.y,
ratio_a * _a.z + ratio_b * _b.z, ratio_a * _a.w + ratio_b * _b.w);
}
// Computes the transformation of a Quaternion and a vector _v.
// This is equivalent to carrying out the quaternion multiplications:
// _q.conjugate() * (*this) * _q
OZZ_INLINE Float3 TransformVector(const Quaternion& _q, const Float3& _v) {
// http://www.neil.dantam.name/note/dantam-quaternion.pdf
// _v + 2.f * cross(_q.xyz, cross(_q.xyz, _v) + _q.w * _v);
const Float3 a(_q.y * _v.z - _q.z * _v.y + _v.x * _q.w,
_q.z * _v.x - _q.x * _v.z + _v.y * _q.w,
_q.x * _v.y - _q.y * _v.x + _v.z * _q.w);
const Float3 b(_q.y * a.z - _q.z * a.y, _q.z * a.x - _q.x * a.z,
_q.x * a.y - _q.y * a.x);
return Float3(_v.x + b.x + b.x, _v.y + b.y + b.y, _v.z + b.z + b.z);
}
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_QUATERNION_H_
+99
View File
@@ -0,0 +1,99 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_RECT_H_
#define OZZ_OZZ_BASE_MATHS_RECT_H_
namespace ozz {
namespace math {
// Defines a rectangle by the integer coordinates of its lower-left and
// width-height.
struct RectInt {
// Constructs a uninitialized rectangle.
RectInt() {}
// Constructs a rectangle with the specified arguments.
RectInt(int _left, int _bottom, int _width, int _height)
: left(_left), bottom(_bottom), width(_width), height(_height) {}
// Tests whether _x and _y coordinates are within rectangle bounds.
bool is_inside(int _x, int _y) const {
return _x >= left && _x < left + width && _y >= bottom &&
_y < bottom + height;
}
// Gets the rectangle x coordinate of the right rectangle side.
int right() const { return left + width; }
// Gets the rectangle y coordinate of the top rectangle side.
int top() const { return bottom + height; }
// Specifies the x-coordinate of the lower side.
int left;
// Specifies the x-coordinate of the left side.
int bottom;
// Specifies the width of the rectangle.
int width;
// Specifies the height of the rectangle..
int height;
};
// Defines a rectangle by the floating point coordinates of its lower-left
// and width-height.
struct RectFloat {
// Constructs a uninitialized rectangle.
RectFloat() {}
// Constructs a rectangle with the specified arguments.
RectFloat(float _left, float _bottom, float _width, float _height)
: left(_left), bottom(_bottom), width(_width), height(_height) {}
// Tests whether _x and _y coordinates are within rectangle bounds
bool is_inside(float _x, float _y) const {
return _x >= left && _x < left + width && _y >= bottom &&
_y < bottom + height;
}
// Gets the rectangle x coordinate of the right rectangle side.
float right() const { return left + width; }
// Gets the rectangle y coordinate of the top rectangle side.
float top() const { return bottom + height; }
// Specifies the x-coordinate of the lower side.
float left;
// Specifies the x-coordinate of the left side.
float bottom;
// Specifies the width of the rectangle.
float width;
// Specifies the height of the rectangle.
float height;
};
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_RECT_H_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,65 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SIMD_MATH_ARCHIVE_H_
#define OZZ_OZZ_BASE_MATHS_SIMD_MATH_ARCHIVE_H_
#include "ozz/base/io/archive_traits.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SimdFloat4)
template <>
struct Extern<math::SimdFloat4> {
static void Save(OArchive& _archive, const math::SimdFloat4* _values,
size_t _count);
static void Load(IArchive& _archive, math::SimdFloat4* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SimdInt4)
template <>
struct Extern<math::SimdInt4> {
static void Save(OArchive& _archive, const math::SimdInt4* _values,
size_t _count);
static void Load(IArchive& _archive, math::SimdInt4* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float4x4)
template <>
struct Extern<math::Float4x4> {
static void Save(OArchive& _archive, const math::Float4x4* _values,
size_t _count);
static void Load(IArchive& _archive, math::Float4x4* _values, size_t _count,
uint32_t _version);
};
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_SIMD_MATH_ARCHIVE_H_
@@ -0,0 +1,274 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SIMD_QUATERNION_H_
#define OZZ_OZZ_BASE_MATHS_SIMD_QUATERNION_H_
#include "ozz/base/maths/simd_math.h"
#include <cmath>
// Implement simd quaternion.
namespace ozz {
namespace math {
// Declare the Quaternion type.
struct SimdQuaternion {
SimdFloat4 xyzw;
// Returns the identity quaternion.
static OZZ_INLINE SimdQuaternion identity() {
const SimdQuaternion quat = {simd_float4::w_axis()};
return quat;
}
// the angle in radian.
static OZZ_INLINE SimdQuaternion FromAxisAngle(_SimdFloat4 _axis,
_SimdFloat4 _angle);
// Returns a normalized quaternion initialized from an axis and angle cosine
// representation.
// Assumes the axis part (x, y, z) of _axis_angle is normalized.
// _angle.x is the angle cosine in radian, it must be within [-1,1] range.
static OZZ_INLINE SimdQuaternion FromAxisCosAngle(_SimdFloat4 _axis,
_SimdFloat4 _cos);
// Returns the quaternion that will rotate vector _from into vector _to,
// around their plan perpendicular axis.The input vectors don't need to be
// normalized, they can be null also.
static OZZ_INLINE SimdQuaternion FromVectors(_SimdFloat4 _from,
_SimdFloat4 _to);
// Returns the quaternion that will rotate vector _from into vector _to,
// around their plan perpendicular axis. The input vectors must be normalized.
static OZZ_INLINE SimdQuaternion FromUnitVectors(_SimdFloat4 _from,
_SimdFloat4 _to);
// Returns a normalized quaternion initialized from an axis angle
// representation.
// Assumes the axis part (x, y, z) of _axis_angle is normalized. _angle.x is
};
// Returns the multiplication of _a and _b. If both _a and _b are normalized,
// then the result is normalized.
OZZ_INLINE SimdQuaternion operator*(const SimdQuaternion& _a,
const SimdQuaternion& _b) {
// Original quaternion multiplication can be swizzled in a simd friendly way
// if w is negated, and some w multiplications parts (1st/last) are swaped.
//
// p1 p2 p3 p4
// _a.w * _b.x + _a.x * _b.w + _a.y * _b.z - _a.z * _b.y
// _a.w * _b.y + _a.y * _b.w + _a.z * _b.x - _a.x * _b.z
// _a.w * _b.z + _a.z * _b.w + _a.x * _b.y - _a.y * _b.x
// _a.w * _b.w - _a.x * _b.x - _a.y * _b.y - _a.z * _b.z
// ... becomes ->
// _a.w * _b.x + _a.x * _b.w + _a.y * _b.z - _a.z * _b.y
// _a.w * _b.y + _a.y * _b.w + _a.z * _b.x - _a.x * _b.z
// _a.w * _b.z + _a.z * _b.w + _a.x * _b.y - _a.y * _b.x
// - (_a.z * _b.z + _a.x * _b.x + _a.y * _b.y - _a.w * _b.w)
const SimdFloat4 p1 =
Swizzle<3, 3, 3, 2>(_a.xyzw) * Swizzle<0, 1, 2, 2>(_b.xyzw);
const SimdFloat4 p2 =
Swizzle<0, 1, 2, 0>(_a.xyzw) * Swizzle<3, 3, 3, 0>(_b.xyzw);
const SimdFloat4 p13 =
MAdd(Swizzle<1, 2, 0, 1>(_a.xyzw), Swizzle<2, 0, 1, 1>(_b.xyzw), p1);
const SimdFloat4 p24 =
NMAdd(Swizzle<2, 0, 1, 3>(_a.xyzw), Swizzle<1, 2, 0, 3>(_b.xyzw), p2);
const SimdQuaternion quat = {Xor(p13 + p24, simd_int4::mask_sign_w())};
return quat;
}
// Returns the conjugate of _q. This is the same as the inverse if _q is
// normalized. Otherwise the magnitude of the inverse is 1.f/|_q|.
OZZ_INLINE SimdQuaternion Conjugate(const SimdQuaternion& _q) {
const SimdQuaternion quat = {Xor(_q.xyzw, simd_int4::mask_sign_xyz())};
return quat;
}
// Returns the negate of _q. This represent the same rotation as q.
OZZ_INLINE SimdQuaternion operator-(const SimdQuaternion& _q) {
const SimdQuaternion quat = {Xor(_q.xyzw, simd_int4::mask_sign())};
return quat;
}
// Returns the normalized quaternion _q.
OZZ_INLINE SimdQuaternion Normalize(const SimdQuaternion& _q) {
const SimdQuaternion quat = {Normalize4(_q.xyzw)};
return quat;
}
// Returns the normalized quaternion _q if the norm of _q is not 0.
// Otherwise returns _safer.
OZZ_INLINE SimdQuaternion NormalizeSafe(const SimdQuaternion& _q,
const SimdQuaternion& _safer) {
const SimdQuaternion quat = {NormalizeSafe4(_q.xyzw, _safer.xyzw)};
return quat;
}
// Returns the estimated normalized quaternion _q.
OZZ_INLINE SimdQuaternion NormalizeEst(const SimdQuaternion& _q) {
const SimdQuaternion quat = {NormalizeEst4(_q.xyzw)};
return quat;
}
// Returns the estimated normalized quaternion _q if the norm of _q is not 0.
// Otherwise returns _safer.
OZZ_INLINE SimdQuaternion NormalizeSafeEst(const SimdQuaternion& _q,
const SimdQuaternion& _safer) {
const SimdQuaternion quat = {NormalizeSafeEst4(_q.xyzw, _safer.xyzw)};
return quat;
}
// Tests if the _q is a normalized quaternion.
// Returns the result in the x component of the returned vector. y, z and w are
// set to 0.
OZZ_INLINE SimdInt4 IsNormalized(const SimdQuaternion& _q) {
return IsNormalized4(_q.xyzw);
}
// Tests if the _q is a normalized quaternion.
// Uses the estimated normalization coefficient, that matches estimated math
// functions (RecpEst, MormalizeEst...).
// Returns the result in the x component of the returned vector. y, z and w are
// set to 0.
OZZ_INLINE SimdInt4 IsNormalizedEst(const SimdQuaternion& _q) {
return IsNormalizedEst4(_q.xyzw);
}
OZZ_INLINE SimdQuaternion SimdQuaternion::FromAxisAngle(_SimdFloat4 _axis,
_SimdFloat4 _angle) {
assert(AreAllTrue1(IsNormalizedEst3(_axis)) && "axis is not normalized.");
const SimdFloat4 half_angle = _angle * simd_float4::Load1(.5f);
const SimdFloat4 half_sin = SinX(half_angle);
const SimdFloat4 half_cos = CosX(half_angle);
const SimdQuaternion quat = {SetW(_axis * SplatX(half_sin), half_cos)};
return quat;
}
OZZ_INLINE SimdQuaternion SimdQuaternion::FromAxisCosAngle(_SimdFloat4 _axis,
_SimdFloat4 _cos) {
const SimdFloat4 one = simd_float4::one();
const SimdFloat4 half = simd_float4::Load1(.5f);
assert(AreAllTrue1(IsNormalizedEst3(_axis)) && "axis is not normalized.");
assert(AreAllTrue1(And(CmpGe(_cos, -one), CmpLe(_cos, one))) &&
"cos is not in [-1,1] range.");
const SimdFloat4 half_cos2 = (one + _cos) * half;
const SimdFloat4 half_sin2 = one - half_cos2;
const SimdFloat4 half_sincos2 = SetY(half_cos2, half_sin2);
const SimdFloat4 half_sincos = Sqrt(half_sincos2);
const SimdFloat4 half_sin = SplatY(half_sincos);
const SimdQuaternion quat = {SetW(_axis * half_sin, half_sincos)};
return quat;
}
// Returns to an axis angle representation of quaternion _q.
// Assumes quaternion _q is normalized.
OZZ_INLINE SimdFloat4 ToAxisAngle(const SimdQuaternion& _q) {
assert(AreAllTrue1(IsNormalizedEst4(_q.xyzw)) && "_q is not normalized.");
const SimdFloat4 x_axis = simd_float4::x_axis();
const SimdFloat4 clamped_w = Clamp(-x_axis, SplatW(_q.xyzw), x_axis);
const SimdFloat4 half_angle = ACosX(clamped_w);
// Assuming quaternion is normalized then s always positive.
const SimdFloat4 s = SplatX(SqrtX(NMAdd(clamped_w, clamped_w, x_axis)));
// If s is close to zero then direction of axis is not important.
const SimdInt4 low = CmpLt(s, simd_float4::Load1(1e-3f));
return Select(low, x_axis,
SetW(_q.xyzw * RcpEstNR(s), half_angle + half_angle));
}
OZZ_INLINE SimdQuaternion SimdQuaternion::FromVectors(_SimdFloat4 _from,
_SimdFloat4 _to) {
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
const SimdFloat4 norm_from_norm_to =
SqrtX(Length3Sqr(_from) * Length3Sqr(_to));
const float norm_from_norm_to_x = GetX(norm_from_norm_to);
if (norm_from_norm_to_x < 1.e-6f) {
return SimdQuaternion::identity();
}
const SimdFloat4 real_part = norm_from_norm_to + Dot3(_from, _to);
SimdQuaternion quat;
if (GetX(real_part) < 1.e-6f * norm_from_norm_to_x) {
// If _from and _to are exactly opposite, rotate 180 degrees around an
// arbitrary orthogonal axis. Axis normalization can happen later, when we
// normalize the quaternion.
float from[4];
ozz::math::StorePtrU(_from, from);
quat.xyzw = std::abs(from[0]) > std::abs(from[2])
? ozz::math::simd_float4::Load(-from[1], from[0], 0.f, 0.f)
: ozz::math::simd_float4::Load(0.f, -from[2], from[1], 0.f);
} else {
// This is the general code path.
quat.xyzw = SetW(Cross3(_from, _to), real_part);
}
return Normalize(quat);
}
OZZ_INLINE SimdQuaternion SimdQuaternion::FromUnitVectors(_SimdFloat4 _from,
_SimdFloat4 _to) {
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
assert(ozz::math::AreAllTrue1(
And(IsNormalizedEst3(_from), IsNormalizedEst3(_to))) &&
"Input vectors must be normalized.");
const SimdFloat4 real_part =
ozz::math::simd_float4::x_axis() + Dot3(_from, _to);
if (GetX(real_part) < 1.e-6f) {
// If _from and _to are exactly opposite, rotate 180 degrees around an
// arbitrary orthogonal axis.
// Normalization isn't needed, as from is already.
float from[4];
ozz::math::StorePtrU(_from, from);
SimdQuaternion quat = {
std::abs(from[0]) > std::abs(from[2])
? ozz::math::simd_float4::Load(-from[1], from[0], 0.f, 0.f)
: ozz::math::simd_float4::Load(0.f, -from[2], from[1], 0.f)};
return quat;
} else {
// This is the general code path.
SimdQuaternion quat = {SetW(Cross3(_from, _to), real_part)};
return Normalize(quat);
}
}
// Computes the transformation of a Quaternion and a vector _v.
// This is equivalent to carrying out the quaternion multiplications:
// _q.conjugate() * (*this) * _q
// w component of the returned vector is undefined.
OZZ_INLINE SimdFloat4 TransformVector(const SimdQuaternion& _q,
_SimdFloat4 _v) {
// http://www.neil.dantam.name/note/dantam-quaternion.pdf
// _v + 2.f * cross(_q.xyz, cross(_q.xyz, _v) + _q.w * _v)
const SimdFloat4 cross1 = MAdd(SplatW(_q.xyzw), _v, Cross3(_q.xyzw, _v));
const SimdFloat4 cross2 = Cross3(_q.xyzw, cross1);
return _v + cross2 + cross2;
}
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_SIMD_QUATERNION_H_
@@ -0,0 +1,676 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SOA_FLOAT_H_
#define OZZ_OZZ_BASE_MATHS_SOA_FLOAT_H_
#include <cassert>
#include "ozz/base/maths/math_constant.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
struct SoaFloat2 {
SimdFloat4 x, y;
static OZZ_INLINE SoaFloat2 Load(_SimdFloat4 _x, _SimdFloat4 _y) {
const SoaFloat2 r = {_x, _y};
return r;
}
static OZZ_INLINE SoaFloat2 zero() {
const SoaFloat2 r = {simd_float4::zero(), simd_float4::zero()};
return r;
}
static OZZ_INLINE SoaFloat2 one() {
const SoaFloat2 r = {simd_float4::one(), simd_float4::one()};
return r;
}
static OZZ_INLINE SoaFloat2 x_axis() {
const SoaFloat2 r = {simd_float4::one(), simd_float4::zero()};
return r;
}
static OZZ_INLINE SoaFloat2 y_axis() {
const SoaFloat2 r = {simd_float4::zero(), simd_float4::one()};
return r;
}
};
struct SoaFloat3 {
SimdFloat4 x, y, z;
static OZZ_INLINE SoaFloat3 Load(_SimdFloat4 _x, _SimdFloat4 _y,
_SimdFloat4 _z) {
const SoaFloat3 r = {_x, _y, _z};
return r;
}
static OZZ_INLINE SoaFloat3 Load(const SoaFloat2& _v, _SimdFloat4 _z) {
const SoaFloat3 r = {_v.x, _v.y, _z};
return r;
}
static OZZ_INLINE SoaFloat3 zero() {
const SoaFloat3 r = {simd_float4::zero(), simd_float4::zero(),
simd_float4::zero()};
return r;
}
static OZZ_INLINE SoaFloat3 one() {
const SoaFloat3 r = {simd_float4::one(), simd_float4::one(),
simd_float4::one()};
return r;
}
static OZZ_INLINE SoaFloat3 x_axis() {
const SoaFloat3 r = {simd_float4::one(), simd_float4::zero(),
simd_float4::zero()};
return r;
}
static OZZ_INLINE SoaFloat3 y_axis() {
const SoaFloat3 r = {simd_float4::zero(), simd_float4::one(),
simd_float4::zero()};
return r;
}
static OZZ_INLINE SoaFloat3 z_axis() {
const SoaFloat3 r = {simd_float4::zero(), simd_float4::zero(),
simd_float4::one()};
return r;
}
};
struct SoaFloat4 {
SimdFloat4 x, y, z, w;
static OZZ_INLINE SoaFloat4 Load(_SimdFloat4 _x, _SimdFloat4 _y,
_SimdFloat4 _z, const SimdFloat4& _w) {
const SoaFloat4 r = {_x, _y, _z, _w};
return r;
}
static OZZ_INLINE SoaFloat4 Load(const SoaFloat3& _v, _SimdFloat4 _w) {
const SoaFloat4 r = {_v.x, _v.y, _v.z, _w};
return r;
}
static OZZ_INLINE SoaFloat4 Load(const SoaFloat2& _v, _SimdFloat4 _z,
_SimdFloat4 _w) {
const SoaFloat4 r = {_v.x, _v.y, _z, _w};
return r;
}
static OZZ_INLINE SoaFloat4 zero() {
const SimdFloat4 zero = simd_float4::zero();
const SoaFloat4 r = {zero, zero, zero, zero};
return r;
}
static OZZ_INLINE SoaFloat4 one() {
const SimdFloat4 one = simd_float4::one();
const SoaFloat4 r = {one, one, one, one};
return r;
}
static OZZ_INLINE SoaFloat4 x_axis() {
const SimdFloat4 zero = simd_float4::zero();
const SoaFloat4 r = {simd_float4::one(), zero, zero, zero};
return r;
}
static OZZ_INLINE SoaFloat4 y_axis() {
const SimdFloat4 zero = simd_float4::zero();
const SoaFloat4 r = {zero, simd_float4::one(), zero, zero};
return r;
}
static OZZ_INLINE SoaFloat4 z_axis() {
const SimdFloat4 zero = simd_float4::zero();
const SoaFloat4 r = {zero, zero, simd_float4::one(), zero};
return r;
}
static OZZ_INLINE SoaFloat4 w_axis() {
const SimdFloat4 zero = simd_float4::zero();
const SoaFloat4 r = {zero, zero, zero, simd_float4::one()};
return r;
}
};
} // namespace math
} // namespace ozz
// Returns per element addition of _a and _b using operator +.
OZZ_INLINE ozz::math::SoaFloat4 operator+(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SoaFloat4 r = {_a.x + _b.x, _a.y + _b.y, _a.z + _b.z,
_a.w + _b.w};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator+(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SoaFloat3 r = {_a.x + _b.x, _a.y + _b.y, _a.z + _b.z};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator+(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SoaFloat2 r = {_a.x + _b.x, _a.y + _b.y};
return r;
}
// Returns per element subtraction of _a and _b using operator -.
OZZ_INLINE ozz::math::SoaFloat4 operator-(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SoaFloat4 r = {_a.x - _b.x, _a.y - _b.y, _a.z - _b.z,
_a.w - _b.w};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator-(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SoaFloat3 r = {_a.x - _b.x, _a.y - _b.y, _a.z - _b.z};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator-(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SoaFloat2 r = {_a.x - _b.x, _a.y - _b.y};
return r;
}
// Returns per element negative value of _v.
OZZ_INLINE ozz::math::SoaFloat4 operator-(const ozz::math::SoaFloat4& _v) {
const ozz::math::SoaFloat4 r = {-_v.x, -_v.y, -_v.z, -_v.w};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator-(const ozz::math::SoaFloat3& _v) {
const ozz::math::SoaFloat3 r = {-_v.x, -_v.y, -_v.z};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator-(const ozz::math::SoaFloat2& _v) {
const ozz::math::SoaFloat2 r = {-_v.x, -_v.y};
return r;
}
// Returns per element multiplication of _a and _b using operator *.
OZZ_INLINE ozz::math::SoaFloat4 operator*(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SoaFloat4 r = {_a.x * _b.x, _a.y * _b.y, _a.z * _b.z,
_a.w * _b.w};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator*(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SoaFloat3 r = {_a.x * _b.x, _a.y * _b.y, _a.z * _b.z};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator*(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SoaFloat2 r = {_a.x * _b.x, _a.y * _b.y};
return r;
}
// Returns per element multiplication of _a and scalar value _f using
// operator *.
OZZ_INLINE ozz::math::SoaFloat4 operator*(const ozz::math::SoaFloat4& _a,
ozz::math::_SimdFloat4 _f) {
const ozz::math::SoaFloat4 r = {_a.x * _f, _a.y * _f, _a.z * _f, _a.w * _f};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator*(const ozz::math::SoaFloat3& _a,
ozz::math::_SimdFloat4 _f) {
const ozz::math::SoaFloat3 r = {_a.x * _f, _a.y * _f, _a.z * _f};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator*(const ozz::math::SoaFloat2& _a,
ozz::math::_SimdFloat4 _f) {
const ozz::math::SoaFloat2 r = {_a.x * _f, _a.y * _f};
return r;
}
// Multiplies _a and _b, then adds _addend.
// v = (_a * _b) + _addend
OZZ_INLINE ozz::math::SoaFloat2 MAdd(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b,
const ozz::math::SoaFloat2& _addend) {
const ozz::math::SoaFloat2 r = {ozz::math::MAdd(_a.x, _b.x, _addend.x),
ozz::math::MAdd(_a.y, _b.y, _addend.y)};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 MAdd(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b,
const ozz::math::SoaFloat3& _addend) {
const ozz::math::SoaFloat3 r = {ozz::math::MAdd(_a.x, _b.x, _addend.x),
ozz::math::MAdd(_a.y, _b.y, _addend.y),
ozz::math::MAdd(_a.z, _b.z, _addend.z)};
return r;
}
OZZ_INLINE ozz::math::SoaFloat4 MAdd(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b,
const ozz::math::SoaFloat4& _addend) {
const ozz::math::SoaFloat4 r = {ozz::math::MAdd(_a.x, _b.x, _addend.x),
ozz::math::MAdd(_a.y, _b.y, _addend.y),
ozz::math::MAdd(_a.z, _b.z, _addend.z),
ozz::math::MAdd(_a.w, _b.w, _addend.w)};
return r;
}
// Returns per element division of _a and _b using operator /.
OZZ_INLINE ozz::math::SoaFloat4 operator/(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SoaFloat4 r = {_a.x / _b.x, _a.y / _b.y, _a.z / _b.z,
_a.w / _b.w};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator/(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SoaFloat3 r = {_a.x / _b.x, _a.y / _b.y, _a.z / _b.z};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator/(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SoaFloat2 r = {_a.x / _b.x, _a.y / _b.y};
return r;
}
// Returns per element division of _a and scalar value _f using operator/.
OZZ_INLINE ozz::math::SoaFloat4 operator/(const ozz::math::SoaFloat4& _a,
ozz::math::_SimdFloat4 _f) {
const ozz::math::SoaFloat4 r = {_a.x / _f, _a.y / _f, _a.z / _f, _a.w / _f};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator/(const ozz::math::SoaFloat3& _a,
ozz::math::_SimdFloat4 _f) {
const ozz::math::SoaFloat3 r = {_a.x / _f, _a.y / _f, _a.z / _f};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator/(const ozz::math::SoaFloat2& _a,
ozz::math::_SimdFloat4 _f) {
const ozz::math::SoaFloat2 r = {_a.x / _f, _a.y / _f};
return r;
}
// Returns true if each element of a is less than each element of _b.
OZZ_INLINE ozz::math::SimdInt4 operator<(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpLt(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpLt(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpLt(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpLt(_a.w, _b.w);
return ozz::math::And(ozz::math::And(ozz::math::And(x, y), z), w);
}
OZZ_INLINE ozz::math::SimdInt4 operator<(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpLt(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpLt(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpLt(_a.z, _b.z);
return ozz::math::And(ozz::math::And(x, y), z);
}
OZZ_INLINE ozz::math::SimdInt4 operator<(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpLt(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpLt(_a.y, _b.y);
return ozz::math::And(x, y);
}
// Returns true if each element of a is less or equal to each element of _b.
OZZ_INLINE ozz::math::SimdInt4 operator<=(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpLe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpLe(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpLe(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpLe(_a.w, _b.w);
return ozz::math::And(ozz::math::And(ozz::math::And(x, y), z), w);
}
OZZ_INLINE ozz::math::SimdInt4 operator<=(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpLe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpLe(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpLe(_a.z, _b.z);
return ozz::math::And(ozz::math::And(x, y), z);
}
OZZ_INLINE ozz::math::SimdInt4 operator<=(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpLe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpLe(_a.y, _b.y);
return ozz::math::And(x, y);
}
// Returns true if each element of a is greater than each element of _b.
OZZ_INLINE ozz::math::SimdInt4 operator>(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpGt(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpGt(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpGt(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpGt(_a.w, _b.w);
return ozz::math::And(ozz::math::And(ozz::math::And(x, y), z), w);
}
OZZ_INLINE ozz::math::SimdInt4 operator>(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpGt(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpGt(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpGt(_a.z, _b.z);
return ozz::math::And(ozz::math::And(x, y), z);
}
OZZ_INLINE ozz::math::SimdInt4 operator>(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpGt(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpGt(_a.y, _b.y);
return ozz::math::And(x, y);
}
// Returns true if each element of a is greater or equal to each element of _b.
OZZ_INLINE ozz::math::SimdInt4 operator>=(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpGe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpGe(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpGe(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpGe(_a.w, _b.w);
return ozz::math::And(ozz::math::And(ozz::math::And(x, y), z), w);
}
OZZ_INLINE ozz::math::SimdInt4 operator>=(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpGe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpGe(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpGe(_a.z, _b.z);
return ozz::math::And(ozz::math::And(x, y), z);
}
OZZ_INLINE ozz::math::SimdInt4 operator>=(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpGe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpGe(_a.y, _b.y);
return ozz::math::And(x, y);
}
// Returns true if each element of _a is equal to each element of _b.
// Uses a bitwise comparison of _a and _b, no tolerance is applied.
OZZ_INLINE ozz::math::SimdInt4 operator==(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpEq(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpEq(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpEq(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpEq(_a.w, _b.w);
return ozz::math::And(ozz::math::And(ozz::math::And(x, y), z), w);
}
OZZ_INLINE ozz::math::SimdInt4 operator==(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpEq(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpEq(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpEq(_a.z, _b.z);
return ozz::math::And(ozz::math::And(x, y), z);
}
OZZ_INLINE ozz::math::SimdInt4 operator==(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpEq(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpEq(_a.y, _b.y);
return ozz::math::And(x, y);
}
// Returns true if each element of a is different from each element of _b.
// Uses a bitwise comparison of _a and _b, no tolerance is applied.
OZZ_INLINE ozz::math::SimdInt4 operator!=(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpNe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpNe(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpNe(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpNe(_a.w, _b.w);
return ozz::math::Or(ozz::math::Or(ozz::math::Or(x, y), z), w);
}
OZZ_INLINE ozz::math::SimdInt4 operator!=(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpNe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpNe(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpNe(_a.z, _b.z);
return ozz::math::Or(ozz::math::Or(x, y), z);
}
OZZ_INLINE ozz::math::SimdInt4 operator!=(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpNe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpNe(_a.y, _b.y);
return ozz::math::Or(x, y);
}
namespace ozz {
namespace math {
// Returns the (horizontal) addition of each element of _v.
OZZ_INLINE SimdFloat4 HAdd(const SoaFloat4& _v) {
return _v.x + _v.y + _v.z + _v.w;
}
OZZ_INLINE SimdFloat4 HAdd(const SoaFloat3& _v) { return _v.x + _v.y + _v.z; }
OZZ_INLINE SimdFloat4 HAdd(const SoaFloat2& _v) { return _v.x + _v.y; }
// Returns the dot product of _a and _b.
OZZ_INLINE SimdFloat4 Dot(const SoaFloat4& _a, const SoaFloat4& _b) {
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
}
OZZ_INLINE SimdFloat4 Dot(const SoaFloat3& _a, const SoaFloat3& _b) {
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z;
}
OZZ_INLINE SimdFloat4 Dot(const SoaFloat2& _a, const SoaFloat2& _b) {
return _a.x * _b.x + _a.y * _b.y;
}
// Returns the cross product of _a and _b.
OZZ_INLINE SoaFloat3 Cross(const SoaFloat3& _a, const SoaFloat3& _b) {
const SoaFloat3 r = {_a.y * _b.z - _b.y * _a.z, _a.z * _b.x - _b.z * _a.x,
_a.x * _b.y - _b.x * _a.y};
return r;
}
// Returns the length |_v| of _v.
OZZ_INLINE SimdFloat4 Length(const SoaFloat4& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
return Sqrt(len2);
}
OZZ_INLINE SimdFloat4 Length(const SoaFloat3& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
return Sqrt(len2);
}
OZZ_INLINE SimdFloat4 Length(const SoaFloat2& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y;
return Sqrt(len2);
}
// Returns the square length |_v|^2 of _v.
OZZ_INLINE SimdFloat4 LengthSqr(const SoaFloat4& _v) {
return _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
}
OZZ_INLINE SimdFloat4 LengthSqr(const SoaFloat3& _v) {
return _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
}
OZZ_INLINE SimdFloat4 LengthSqr(const SoaFloat2& _v) {
return _v.x * _v.x + _v.y * _v.y;
}
// Returns the normalized vector _v.
OZZ_INLINE SoaFloat4 Normalize(const SoaFloat4& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
assert(AreAllTrue(CmpNe(len2, simd_float4::zero())) &&
"_v is not normalizable");
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaFloat4 r = {_v.x * inv_len, _v.y * inv_len, _v.z * inv_len,
_v.w * inv_len};
return r;
}
OZZ_INLINE SoaFloat3 Normalize(const SoaFloat3& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
assert(AreAllTrue(CmpNe(len2, simd_float4::zero())) &&
"_v is not normalizable");
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaFloat3 r = {_v.x * inv_len, _v.y * inv_len, _v.z * inv_len};
return r;
}
OZZ_INLINE SoaFloat2 Normalize(const SoaFloat2& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y;
assert(AreAllTrue(CmpNe(len2, simd_float4::zero())) &&
"_v is not normalizable");
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaFloat2 r = {_v.x * inv_len, _v.y * inv_len};
return r;
}
// Test if each vector _v is normalized.
OZZ_INLINE math::SimdInt4 IsNormalized(const SoaFloat4& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceSq));
}
OZZ_INLINE math::SimdInt4 IsNormalized(const SoaFloat3& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceSq));
}
OZZ_INLINE math::SimdInt4 IsNormalized(const SoaFloat2& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceSq));
}
// Test if each vector _v is normalized using estimated tolerance.
OZZ_INLINE math::SimdInt4 IsNormalizedEst(const SoaFloat4& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceEstSq));
}
OZZ_INLINE math::SimdInt4 IsNormalizedEst(const SoaFloat3& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceEstSq));
}
OZZ_INLINE math::SimdInt4 IsNormalizedEst(const SoaFloat2& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceEstSq));
}
// Returns the normalized vector _v if the norm of _v is not 0.
// Otherwise returns _safer.
OZZ_INLINE SoaFloat4 NormalizeSafe(const SoaFloat4& _v,
const SoaFloat4& _safer) {
assert(AreAllTrue(IsNormalizedEst(_safer)) && "_safer is not normalized");
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
const math::SimdInt4 b = CmpNe(len2, math::simd_float4::zero());
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaFloat4 r = {
Select(b, _v.x * inv_len, _safer.x), Select(b, _v.y * inv_len, _safer.y),
Select(b, _v.z * inv_len, _safer.z), Select(b, _v.w * inv_len, _safer.w)};
return r;
}
OZZ_INLINE SoaFloat3 NormalizeSafe(const SoaFloat3& _v,
const SoaFloat3& _safer) {
assert(AreAllTrue(IsNormalizedEst(_safer)) && "_safer is not normalized");
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
const math::SimdInt4 b = CmpNe(len2, math::simd_float4::zero());
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaFloat3 r = {Select(b, _v.x * inv_len, _safer.x),
Select(b, _v.y * inv_len, _safer.y),
Select(b, _v.z * inv_len, _safer.z)};
return r;
}
OZZ_INLINE SoaFloat2 NormalizeSafe(const SoaFloat2& _v,
const SoaFloat2& _safer) {
assert(AreAllTrue(IsNormalizedEst(_safer)) && "_safer is not normalized");
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y;
const math::SimdInt4 b = CmpNe(len2, math::simd_float4::zero());
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaFloat2 r = {Select(b, _v.x * inv_len, _safer.x),
Select(b, _v.y * inv_len, _safer.y)};
return r;
}
// Returns the linear interpolation of _a and _b with coefficient _f.
// _f is not limited to range [0,1].
OZZ_INLINE SoaFloat4 Lerp(const SoaFloat4& _a, const SoaFloat4& _b,
_SimdFloat4 _f) {
const SoaFloat4 r = {(_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w};
return r;
}
OZZ_INLINE SoaFloat3 Lerp(const SoaFloat3& _a, const SoaFloat3& _b,
_SimdFloat4 _f) {
const SoaFloat3 r = {(_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z};
return r;
}
OZZ_INLINE SoaFloat2 Lerp(const SoaFloat2& _a, const SoaFloat2& _b,
_SimdFloat4 _f) {
const SoaFloat2 r = {(_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y};
return r;
}
// Returns the minimum of each element of _a and _b.
OZZ_INLINE SoaFloat4 Min(const SoaFloat4& _a, const SoaFloat4& _b) {
const SoaFloat4 r = {Min(_a.x, _b.x), Min(_a.y, _b.y), Min(_a.z, _b.z),
Min(_a.w, _b.w)};
return r;
}
OZZ_INLINE SoaFloat3 Min(const SoaFloat3& _a, const SoaFloat3& _b) {
const SoaFloat3 r = {Min(_a.x, _b.x), Min(_a.y, _b.y), Min(_a.z, _b.z)};
return r;
}
OZZ_INLINE SoaFloat2 Min(const SoaFloat2& _a, const SoaFloat2& _b) {
const SoaFloat2 r = {Min(_a.x, _b.x), Min(_a.y, _b.y)};
return r;
}
// Returns the maximum of each element of _a and _b.
OZZ_INLINE SoaFloat4 Max(const SoaFloat4& _a, const SoaFloat4& _b) {
const SoaFloat4 r = {Max(_a.x, _b.x), Max(_a.y, _b.y), Max(_a.z, _b.z),
Max(_a.w, _b.w)};
return r;
}
OZZ_INLINE SoaFloat3 Max(const SoaFloat3& _a, const SoaFloat3& _b) {
const SoaFloat3 r = {Max(_a.x, _b.x), Max(_a.y, _b.y), Max(_a.z, _b.z)};
return r;
}
OZZ_INLINE SoaFloat2 Max(const SoaFloat2& _a, const SoaFloat2& _b) {
const SoaFloat2 r = {Max(_a.x, _b.x), Max(_a.y, _b.y)};
return r;
}
// Clamps each element of _x between _a and _b.
// _a must be less or equal to b;
OZZ_INLINE SoaFloat4 Clamp(const SoaFloat4& _a, const SoaFloat4& _v,
const SoaFloat4& _b) {
return Max(_a, Min(_v, _b));
}
OZZ_INLINE SoaFloat3 Clamp(const SoaFloat3& _a, const SoaFloat3& _v,
const SoaFloat3& _b) {
return Max(_a, Min(_v, _b));
}
OZZ_INLINE SoaFloat2 Clamp(const SoaFloat2& _a, const SoaFloat2& _v,
const SoaFloat2& _b) {
return Max(_a, Min(_v, _b));
}
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_SOA_FLOAT_H_
@@ -0,0 +1,276 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SOA_FLOAT4X4_H_
#define OZZ_OZZ_BASE_MATHS_SOA_FLOAT4X4_H_
#include <cassert>
#include "ozz/base/maths/soa_float.h"
#include "ozz/base/maths/soa_quaternion.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
// Declare the 4x4 soa matrix type. Uses the column major convention where the
// matrix-times-vector is written v'=Mv:
// [ m.cols[0].x m.cols[1].x m.cols[2].x m.cols[3].x ] {v.x}
// | m.cols[0].y m.cols[1].y m.cols[2].y m.cols[3].y | * {v.y}
// | m.cols[0].z m.cols[1].y m.cols[2].y m.cols[3].y | {v.z}
// [ m.cols[0].w m.cols[1].w m.cols[2].w m.cols[3].w ] {v.1}
struct SoaFloat4x4 {
// Soa matrix columns.
SoaFloat4 cols[4];
// Returns the identity matrix.
static OZZ_INLINE SoaFloat4x4 identity() {
const SimdFloat4 zero = simd_float4::zero();
const SimdFloat4 one = simd_float4::one();
SoaFloat4x4 ret = {{{one, zero, zero, zero},
{zero, one, zero, zero},
{zero, zero, one, zero},
{zero, zero, zero, one}}};
return ret;
}
// Returns a scaling matrix that scales along _v.
// _v.w is ignored.
static OZZ_INLINE SoaFloat4x4 Scaling(const SoaFloat4& _v) {
const SimdFloat4 zero = simd_float4::zero();
const SimdFloat4 one = simd_float4::one();
const SoaFloat4x4 ret = {{{_v.x, zero, zero, zero},
{zero, _v.y, zero, zero},
{zero, zero, _v.z, zero},
{zero, zero, zero, one}}};
return ret;
}
// Returns the rotation matrix built from quaternion defined by x, y, z and w
// components of _v.
static OZZ_INLINE SoaFloat4x4 FromQuaternion(const SoaQuaternion& _q) {
assert(AreAllTrue(IsNormalizedEst(_q)));
const SimdFloat4 zero = simd_float4::zero();
const SimdFloat4 one = simd_float4::one();
const SimdFloat4 two = one + one;
const SimdFloat4 xx = _q.x * _q.x;
const SimdFloat4 xy = _q.x * _q.y;
const SimdFloat4 xz = _q.x * _q.z;
const SimdFloat4 xw = _q.x * _q.w;
const SimdFloat4 yy = _q.y * _q.y;
const SimdFloat4 yz = _q.y * _q.z;
const SimdFloat4 yw = _q.y * _q.w;
const SimdFloat4 zz = _q.z * _q.z;
const SimdFloat4 zw = _q.z * _q.w;
const SoaFloat4x4 ret = {
{{one - two * (yy + zz), two * (xy + zw), two * (xz - yw), zero},
{two * (xy - zw), one - two * (xx + zz), two * (yz + xw), zero},
{two * (xz + yw), two * (yz - xw), one - two * (xx + yy), zero},
{zero, zero, zero, one}}};
return ret;
}
// Returns the affine transformation matrix built from split translation,
// rotation (quaternion) and scale.
static OZZ_INLINE SoaFloat4x4 FromAffine(const SoaFloat3& _translation,
const SoaQuaternion& _quaternion,
const SoaFloat3& _scale) {
assert(AreAllTrue(IsNormalizedEst(_quaternion)));
const SimdFloat4 zero = simd_float4::zero();
const SimdFloat4 one = simd_float4::one();
const SimdFloat4 two = one + one;
const SimdFloat4 xx = _quaternion.x * _quaternion.x;
const SimdFloat4 xy = _quaternion.x * _quaternion.y;
const SimdFloat4 xz = _quaternion.x * _quaternion.z;
const SimdFloat4 xw = _quaternion.x * _quaternion.w;
const SimdFloat4 yy = _quaternion.y * _quaternion.y;
const SimdFloat4 yz = _quaternion.y * _quaternion.z;
const SimdFloat4 yw = _quaternion.y * _quaternion.w;
const SimdFloat4 zz = _quaternion.z * _quaternion.z;
const SimdFloat4 zw = _quaternion.z * _quaternion.w;
const SoaFloat4x4 ret = {
{{_scale.x * (one - two * (yy + zz)), _scale.x * two * (xy + zw),
_scale.x * two * (xz - yw), zero},
{_scale.y * two * (xy - zw), _scale.y * (one - two * (xx + zz)),
_scale.y * two * (yz + xw), zero},
{_scale.z * two * (xz + yw), _scale.z * two * (yz - xw),
_scale.z * (one - two * (xx + yy)), zero},
{_translation.x, _translation.y, _translation.z, one}}};
return ret;
}
};
// Returns the transpose of matrix _m.
OZZ_INLINE SoaFloat4x4 Transpose(const SoaFloat4x4& _m) {
const SoaFloat4x4 ret = {
{{_m.cols[0].x, _m.cols[1].x, _m.cols[2].x, _m.cols[3].x},
{_m.cols[0].y, _m.cols[1].y, _m.cols[2].y, _m.cols[3].y},
{_m.cols[0].z, _m.cols[1].z, _m.cols[2].z, _m.cols[3].z},
{_m.cols[0].w, _m.cols[1].w, _m.cols[2].w, _m.cols[3].w}}};
return ret;
}
// Returns the inverse of matrix _m.
// If _invertible is not nullptr, each component will be set to true if its
// respective matrix is invertible. If _invertible is nullptr, then an assert is
// triggered in case any of the 4 matrices isn't invertible.
OZZ_INLINE SoaFloat4x4 Invert(const SoaFloat4x4& _m,
SimdInt4* _invertible = nullptr) {
const SoaFloat4* cols = _m.cols;
const SimdFloat4 a00 = cols[2].z * cols[3].w - cols[3].z * cols[2].w;
const SimdFloat4 a01 = cols[2].y * cols[3].w - cols[3].y * cols[2].w;
const SimdFloat4 a02 = cols[2].y * cols[3].z - cols[3].y * cols[2].z;
const SimdFloat4 a03 = cols[2].x * cols[3].w - cols[3].x * cols[2].w;
const SimdFloat4 a04 = cols[2].x * cols[3].z - cols[3].x * cols[2].z;
const SimdFloat4 a05 = cols[2].x * cols[3].y - cols[3].x * cols[2].y;
const SimdFloat4 a06 = cols[1].z * cols[3].w - cols[3].z * cols[1].w;
const SimdFloat4 a07 = cols[1].y * cols[3].w - cols[3].y * cols[1].w;
const SimdFloat4 a08 = cols[1].y * cols[3].z - cols[3].y * cols[1].z;
const SimdFloat4 a09 = cols[1].x * cols[3].w - cols[3].x * cols[1].w;
const SimdFloat4 a10 = cols[1].x * cols[3].z - cols[3].x * cols[1].z;
const SimdFloat4 a11 = cols[1].y * cols[3].w - cols[3].y * cols[1].w;
const SimdFloat4 a12 = cols[1].x * cols[3].y - cols[3].x * cols[1].y;
const SimdFloat4 a13 = cols[1].z * cols[2].w - cols[2].z * cols[1].w;
const SimdFloat4 a14 = cols[1].y * cols[2].w - cols[2].y * cols[1].w;
const SimdFloat4 a15 = cols[1].y * cols[2].z - cols[2].y * cols[1].z;
const SimdFloat4 a16 = cols[1].x * cols[2].w - cols[2].x * cols[1].w;
const SimdFloat4 a17 = cols[1].x * cols[2].z - cols[2].x * cols[1].z;
const SimdFloat4 a18 = cols[1].x * cols[2].y - cols[2].x * cols[1].y;
const SimdFloat4 b0x = cols[1].y * a00 - cols[1].z * a01 + cols[1].w * a02;
const SimdFloat4 b1x = -cols[1].x * a00 + cols[1].z * a03 - cols[1].w * a04;
const SimdFloat4 b2x = cols[1].x * a01 - cols[1].y * a03 + cols[1].w * a05;
const SimdFloat4 b3x = -cols[1].x * a02 + cols[1].y * a04 - cols[1].z * a05;
const SimdFloat4 b0y = -cols[0].y * a00 + cols[0].z * a01 - cols[0].w * a02;
const SimdFloat4 b1y = cols[0].x * a00 - cols[0].z * a03 + cols[0].w * a04;
const SimdFloat4 b2y = -cols[0].x * a01 + cols[0].y * a03 - cols[0].w * a05;
const SimdFloat4 b3y = cols[0].x * a02 - cols[0].y * a04 + cols[0].z * a05;
const SimdFloat4 b0z = cols[0].y * a06 - cols[0].z * a07 + cols[0].w * a08;
const SimdFloat4 b1z = -cols[0].x * a06 + cols[0].z * a09 - cols[0].w * a10;
const SimdFloat4 b2z = cols[0].x * a11 - cols[0].y * a09 + cols[0].w * a12;
const SimdFloat4 b3z = -cols[0].x * a08 + cols[0].y * a10 - cols[0].z * a12;
const SimdFloat4 b0w = -cols[0].y * a13 + cols[0].z * a14 - cols[0].w * a15;
const SimdFloat4 b1w = cols[0].x * a13 - cols[0].z * a16 + cols[0].w * a17;
const SimdFloat4 b2w = -cols[0].x * a14 + cols[0].y * a16 - cols[0].w * a18;
const SimdFloat4 b3w = cols[0].x * a15 - cols[0].y * a17 + cols[0].z * a18;
const SimdFloat4 det =
cols[0].x * b0x + cols[0].y * b1x + cols[0].z * b2x + cols[0].w * b3x;
const SimdInt4 invertible = CmpNe(det, simd_float4::zero());
assert((_invertible || AreAllTrue(invertible)) && "Matrix is not invertible");
if (_invertible != nullptr) {
*_invertible = invertible;
}
const SimdFloat4 inv_det =
Select(invertible, RcpEstNR(det), simd_float4::zero());
const SoaFloat4x4 ret = {
{{b0x * inv_det, b0y * inv_det, b0z * inv_det, b0w * inv_det},
{b1x * inv_det, b1y * inv_det, b1z * inv_det, b1w * inv_det},
{b2x * inv_det, b2y * inv_det, b2z * inv_det, b2w * inv_det},
{b3x * inv_det, b3y * inv_det, b3z * inv_det, b3w * inv_det}}};
return ret;
}
// Scales matrix _m along the axis defined by _v components.
// _v.w is ignored.
OZZ_INLINE SoaFloat4x4 Scale(const SoaFloat4x4& _m, const SoaFloat4& _v) {
const SoaFloat4x4 ret = {{{_m.cols[0].x * _v.x, _m.cols[0].y * _v.x,
_m.cols[0].z * _v.x, _m.cols[0].w * _v.x},
{_m.cols[1].x * _v.y, _m.cols[1].y * _v.y,
_m.cols[1].z * _v.y, _m.cols[1].w * _v.y},
{_m.cols[2].x * _v.z, _m.cols[2].y * _v.z,
_m.cols[2].z * _v.z, _m.cols[2].w * _v.z},
_m.cols[3]}};
return ret;
}
} // namespace math
} // namespace ozz
// Computes the multiplication of matrix Float4x4 and vector _v.
OZZ_INLINE ozz::math::SoaFloat4 operator*(const ozz::math::SoaFloat4x4& _m,
const ozz::math::SoaFloat4& _v) {
const ozz::math::SoaFloat4 ret = {
_m.cols[0].x * _v.x + _m.cols[1].x * _v.y + _m.cols[2].x * _v.z +
_m.cols[3].x * _v.w,
_m.cols[0].y * _v.x + _m.cols[1].y * _v.y + _m.cols[2].y * _v.z +
_m.cols[3].y * _v.w,
_m.cols[0].z * _v.x + _m.cols[1].z * _v.y + _m.cols[2].z * _v.z +
_m.cols[3].z * _v.w,
_m.cols[0].w * _v.x + _m.cols[1].w * _v.y + _m.cols[2].w * _v.z +
_m.cols[3].w * _v.w};
return ret;
}
// Computes the multiplication of two matrices _a and _b.
OZZ_INLINE ozz::math::SoaFloat4x4 operator*(const ozz::math::SoaFloat4x4& _a,
const ozz::math::SoaFloat4x4& _b) {
const ozz::math::SoaFloat4x4 ret = {
{_a * _b.cols[0], _a * _b.cols[1], _a * _b.cols[2], _a * _b.cols[3]}};
return ret;
}
// Computes the per element addition of two matrices _a and _b.
OZZ_INLINE ozz::math::SoaFloat4x4 operator+(const ozz::math::SoaFloat4x4& _a,
const ozz::math::SoaFloat4x4& _b) {
const ozz::math::SoaFloat4x4 ret = {
{{_a.cols[0].x + _b.cols[0].x, _a.cols[0].y + _b.cols[0].y,
_a.cols[0].z + _b.cols[0].z, _a.cols[0].w + _b.cols[0].w},
{_a.cols[1].x + _b.cols[1].x, _a.cols[1].y + _b.cols[1].y,
_a.cols[1].z + _b.cols[1].z, _a.cols[1].w + _b.cols[1].w},
{_a.cols[2].x + _b.cols[2].x, _a.cols[2].y + _b.cols[2].y,
_a.cols[2].z + _b.cols[2].z, _a.cols[2].w + _b.cols[2].w},
{_a.cols[3].x + _b.cols[3].x, _a.cols[3].y + _b.cols[3].y,
_a.cols[3].z + _b.cols[3].z, _a.cols[3].w + _b.cols[3].w}}};
return ret;
}
// Computes the per element subtraction of two matrices _a and _b.
OZZ_INLINE ozz::math::SoaFloat4x4 operator-(const ozz::math::SoaFloat4x4& _a,
const ozz::math::SoaFloat4x4& _b) {
const ozz::math::SoaFloat4x4 ret = {
{{_a.cols[0].x - _b.cols[0].x, _a.cols[0].y - _b.cols[0].y,
_a.cols[0].z - _b.cols[0].z, _a.cols[0].w - _b.cols[0].w},
{_a.cols[1].x - _b.cols[1].x, _a.cols[1].y - _b.cols[1].y,
_a.cols[1].z - _b.cols[1].z, _a.cols[1].w - _b.cols[1].w},
{_a.cols[2].x - _b.cols[2].x, _a.cols[2].y - _b.cols[2].y,
_a.cols[2].z - _b.cols[2].z, _a.cols[2].w - _b.cols[2].w},
{_a.cols[3].x - _b.cols[3].x, _a.cols[3].y - _b.cols[3].y,
_a.cols[3].z - _b.cols[3].z, _a.cols[3].w - _b.cols[3].w}}};
return ret;
}
#endif // OZZ_OZZ_BASE_MATHS_SOA_FLOAT4X4_H_
@@ -0,0 +1,99 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SOA_MATH_ARCHIVE_H_
#define OZZ_OZZ_BASE_MATHS_SOA_MATH_ARCHIVE_H_
#include "ozz/base/io/archive_traits.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
struct SoaFloat2;
struct SoaFloat3;
struct SoaFloat4;
struct SoaQuaternion;
struct SoaFloat4x4;
struct SoaTransform;
} // namespace math
namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat2)
template <>
struct Extern<math::SoaFloat2> {
static void Save(OArchive& _archive, const math::SoaFloat2* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaFloat2* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat3)
template <>
struct Extern<math::SoaFloat3> {
static void Save(OArchive& _archive, const math::SoaFloat3* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaFloat3* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat4)
template <>
struct Extern<math::SoaFloat4> {
static void Save(OArchive& _archive, const math::SoaFloat4* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaFloat4* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaQuaternion)
template <>
struct Extern<math::SoaQuaternion> {
static void Save(OArchive& _archive, const math::SoaQuaternion* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaQuaternion* _values,
size_t _count, uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat4x4)
template <>
struct Extern<math::SoaFloat4x4> {
static void Save(OArchive& _archive, const math::SoaFloat4x4* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaFloat4x4* _values,
size_t _count, uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaTransform)
template <>
struct Extern<math::SoaTransform> {
static void Save(OArchive& _archive, const math::SoaTransform* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaTransform* _values,
size_t _count, uint32_t _version);
};
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_SOA_MATH_ARCHIVE_H_
@@ -0,0 +1,189 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SOA_QUATERNION_H_
#define OZZ_OZZ_BASE_MATHS_SOA_QUATERNION_H_
#include <cassert>
#include "ozz/base/maths/soa_float.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
struct SoaQuaternion {
SimdFloat4 x, y, z, w;
// Loads a quaternion from 4 SimdFloat4 values.
static OZZ_INLINE SoaQuaternion Load(_SimdFloat4 _x, _SimdFloat4 _y,
_SimdFloat4 _z, const SimdFloat4& _w) {
const SoaQuaternion r = {_x, _y, _z, _w};
return r;
}
// Returns the identity SoaQuaternion.
static OZZ_INLINE SoaQuaternion identity() {
const SimdFloat4 zero = simd_float4::zero();
const SoaQuaternion r = {zero, zero, zero, simd_float4::one()};
return r;
}
};
// Returns the conjugate of _q. This is the same as the inverse if _q is
// normalized. Otherwise the magnitude of the inverse is 1.f/|_q|.
OZZ_INLINE SoaQuaternion Conjugate(const SoaQuaternion& _q) {
const SoaQuaternion r = {-_q.x, -_q.y, -_q.z, _q.w};
return r;
}
// Returns the negate of _q. This represent the same rotation as q.
OZZ_INLINE SoaQuaternion operator-(const SoaQuaternion& _q) {
const SoaQuaternion r = {-_q.x, -_q.y, -_q.z, -_q.w};
return r;
}
// Returns the 4D dot product of quaternion _a and _b.
OZZ_INLINE SimdFloat4 Dot(const SoaQuaternion& _a, const SoaQuaternion& _b) {
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
}
// Returns the normalized SoaQuaternion _q.
OZZ_INLINE SoaQuaternion Normalize(const SoaQuaternion& _q) {
const SimdFloat4 len2 = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaQuaternion r = {_q.x * inv_len, _q.y * inv_len, _q.z * inv_len,
_q.w * inv_len};
return r;
}
// Returns the estimated normalized SoaQuaternion _q.
OZZ_INLINE SoaQuaternion NormalizeEst(const SoaQuaternion& _q) {
const SimdFloat4 len2 = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
// Uses RSqrtEstNR (with one more Newton-Raphson step) as quaternions loose
// much precision due to normalization.
const SimdFloat4 inv_len = RSqrtEstNR(len2);
const SoaQuaternion r = {_q.x * inv_len, _q.y * inv_len, _q.z * inv_len,
_q.w * inv_len};
return r;
}
// Test if each quaternion of _q is normalized.
OZZ_INLINE SimdInt4 IsNormalized(const SoaQuaternion& _q) {
const SimdFloat4 len2 = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceSq));
}
// Test if each quaternion of _q is normalized. using estimated tolerance.
OZZ_INLINE SimdInt4 IsNormalizedEst(const SoaQuaternion& _q) {
const SimdFloat4 len2 = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceEstSq));
}
// Returns the linear interpolation of SoaQuaternion _a and _b with coefficient
// _f.
OZZ_INLINE SoaQuaternion Lerp(const SoaQuaternion& _a, const SoaQuaternion& _b,
_SimdFloat4 _f) {
const SoaQuaternion r = {(_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z,
(_b.w - _a.w) * _f + _a.w};
return r;
}
// Returns the linear interpolation of SoaQuaternion _a and _b with coefficient
// _f.
OZZ_INLINE SoaQuaternion NLerp(const SoaQuaternion& _a, const SoaQuaternion& _b,
_SimdFloat4 _f) {
const SoaFloat4 lerp = {(_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w};
const SimdFloat4 len2 =
lerp.x * lerp.x + lerp.y * lerp.y + lerp.z * lerp.z + lerp.w * lerp.w;
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaQuaternion r = {lerp.x * inv_len, lerp.y * inv_len, lerp.z * inv_len,
lerp.w * inv_len};
return r;
}
// Returns the estimated linear interpolation of SoaQuaternion _a and _b with
// coefficient _f.
OZZ_INLINE SoaQuaternion NLerpEst(const SoaQuaternion& _a,
const SoaQuaternion& _b, _SimdFloat4 _f) {
const SoaFloat4 lerp = {(_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w};
const SimdFloat4 len2 =
lerp.x * lerp.x + lerp.y * lerp.y + lerp.z * lerp.z + lerp.w * lerp.w;
// Uses RSqrtEstNR (with one more Newton-Raphson step) as quaternions loose
// much precision due to normalization.
const SimdFloat4 inv_len = RSqrtEstNR(len2);
const SoaQuaternion r = {lerp.x * inv_len, lerp.y * inv_len, lerp.z * inv_len,
lerp.w * inv_len};
return r;
}
} // namespace math
} // namespace ozz
// Returns the addition of _a and _b.
OZZ_INLINE ozz::math::SoaQuaternion operator+(
const ozz::math::SoaQuaternion& _a, const ozz::math::SoaQuaternion& _b) {
const ozz::math::SoaQuaternion r = {_a.x + _b.x, _a.y + _b.y, _a.z + _b.z,
_a.w + _b.w};
return r;
}
// Returns the multiplication of _q and scalar value _f.
OZZ_INLINE ozz::math::SoaQuaternion operator*(
const ozz::math::SoaQuaternion& _q, const ozz::math::SimdFloat4& _f) {
const ozz::math::SoaQuaternion r = {_q.x * _f, _q.y * _f, _q.z * _f,
_q.w * _f};
return r;
}
// Returns the multiplication of _a and _b. If both _a and _b are normalized,
// then the result is normalized.
OZZ_INLINE ozz::math::SoaQuaternion operator*(
const ozz::math::SoaQuaternion& _a, const ozz::math::SoaQuaternion& _b) {
const ozz::math::SoaQuaternion r = {
_a.w * _b.x + _a.x * _b.w + _a.y * _b.z - _a.z * _b.y,
_a.w * _b.y + _a.y * _b.w + _a.z * _b.x - _a.x * _b.z,
_a.w * _b.z + _a.z * _b.w + _a.x * _b.y - _a.y * _b.x,
_a.w * _b.w - _a.x * _b.x - _a.y * _b.y - _a.z * _b.z};
return r;
}
// Returns true if each element of _a is equal to each element of _b.
// Uses a bitwise comparison of _a and _b, no tolerance is applied.
OZZ_INLINE ozz::math::SimdInt4 operator==(const ozz::math::SoaQuaternion& _a,
const ozz::math::SoaQuaternion& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpEq(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpEq(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpEq(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpEq(_a.w, _b.w);
return ozz::math::And(ozz::math::And(ozz::math::And(x, y), z), w);
}
#endif // OZZ_OZZ_BASE_MATHS_SOA_QUATERNION_H_
@@ -0,0 +1,53 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SOA_TRANSFORM_H_
#define OZZ_OZZ_BASE_MATHS_SOA_TRANSFORM_H_
#include "ozz/base/maths/soa_float.h"
#include "ozz/base/maths/soa_quaternion.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
// Stores an affine transformation with separate translation, rotation and scale
// attributes.
struct SoaTransform {
SoaFloat3 translation;
SoaQuaternion rotation;
SoaFloat3 scale;
static OZZ_INLINE SoaTransform identity() {
const SoaTransform ret = {SoaFloat3::zero(), SoaQuaternion::identity(),
SoaFloat3::one()};
return ret;
}
};
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_SOA_TRANSFORM_H_
@@ -0,0 +1,59 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_TRANSFORM_H_
#define OZZ_OZZ_BASE_MATHS_TRANSFORM_H_
#include "ozz/base/maths/quaternion.h"
#include "ozz/base/maths/vec_float.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
// Stores an affine transformation with separate translation, rotation and scale
// attributes.
struct Transform {
// Translation affine transformation component.
Float3 translation;
// Rotation affine transformation component.
Quaternion rotation;
// Scale affine transformation component.
Float3 scale;
// Builds an identity transform.
static OZZ_INLINE Transform identity() {
const Transform ret = {Float3::zero(), Quaternion::identity(),
Float3::one()};
return ret;
}
};
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_TRANSFORM_H_
@@ -0,0 +1,467 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_VEC_FLOAT_H_
#define OZZ_OZZ_BASE_MATHS_VEC_FLOAT_H_
#include <cassert>
#include <cmath>
#include "ozz/base/maths/math_constant.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
// Declares a 2d float vector.
struct Float2 {
float x, y;
// Constructs an uninitialized vector.
OZZ_INLINE Float2() {}
// Constructs a vector initialized with _f value.
explicit OZZ_INLINE Float2(float _f) : x(_f), y(_f) {}
// Constructs a vector initialized with _x and _y values.
OZZ_INLINE Float2(float _x, float _y) : x(_x), y(_y) {}
// Returns a vector with all components set to 0.
static OZZ_INLINE Float2 zero() { return Float2(0.f); }
// Returns a vector with all components set to 1.
static OZZ_INLINE Float2 one() { return Float2(1.f); }
// Returns a unitary vector x.
static OZZ_INLINE Float2 x_axis() { return Float2(1.f, 0.f); }
// Returns a unitary vector y.
static OZZ_INLINE Float2 y_axis() { return Float2(0.f, 1.f); }
};
// Declares a 3d float vector.
struct Float3 {
float x, y, z;
// Constructs an uninitialized vector.
OZZ_INLINE Float3() {}
// Constructs a vector initialized with _f value.
explicit OZZ_INLINE Float3(float _f) : x(_f), y(_f), z(_f) {}
// Constructs a vector initialized with _x, _y and _z values.
OZZ_INLINE Float3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
// Returns a vector initialized with _v.x, _v.y and _z values.
OZZ_INLINE Float3(Float2 _v, float _z) : x(_v.x), y(_v.y), z(_z) {}
// Returns a vector with all components set to 0.
static OZZ_INLINE Float3 zero() { return Float3(0.f); }
// Returns a vector with all components set to 1.
static OZZ_INLINE Float3 one() { return Float3(1.f); }
// Returns a unitary vector x.
static OZZ_INLINE Float3 x_axis() { return Float3(1.f, 0.f, 0.f); }
// Returns a unitary vector y.
static OZZ_INLINE Float3 y_axis() { return Float3(0.f, 1.f, 0.f); }
// Returns a unitary vector z.
static OZZ_INLINE Float3 z_axis() { return Float3(0.f, 0.f, 1.f); }
};
// Declares a 4d float vector.
struct Float4 {
float x, y, z, w;
// Constructs an uninitialized vector.
OZZ_INLINE Float4() {}
// Constructs a vector initialized with _f value.
explicit OZZ_INLINE Float4(float _f) : x(_f), y(_f), z(_f), w(_f) {}
// Constructs a vector initialized with _x, _y, _z and _w values.
OZZ_INLINE Float4(float _x, float _y, float _z, float _w)
: x(_x), y(_y), z(_z), w(_w) {}
// Constructs a vector initialized with _v.x, _v.y, _v.z and _w values.
OZZ_INLINE Float4(Float3 _v, float _w) : x(_v.x), y(_v.y), z(_v.z), w(_w) {}
// Constructs a vector initialized with _v.x, _v.y, _z and _w values.
OZZ_INLINE Float4(Float2 _v, float _z, float _w)
: x(_v.x), y(_v.y), z(_z), w(_w) {}
// Returns a vector with all components set to 0.
static OZZ_INLINE Float4 zero() { return Float4(0.f); }
// Returns a vector with all components set to 1.
static OZZ_INLINE Float4 one() { return Float4(1.f); }
// Returns a unitary vector x.
static OZZ_INLINE Float4 x_axis() { return Float4(1.f, 0.f, 0.f, 0.f); }
// Returns a unitary vector y.
static OZZ_INLINE Float4 y_axis() { return Float4(0.f, 1.f, 0.f, 0.f); }
// Returns a unitary vector z.
static OZZ_INLINE Float4 z_axis() { return Float4(0.f, 0.f, 1.f, 0.f); }
// Returns a unitary vector w.
static OZZ_INLINE Float4 w_axis() { return Float4(0.f, 0.f, 0.f, 1.f); }
};
// Returns per element addition of _a and _b using operator +.
OZZ_INLINE Float4 operator+(const Float4& _a, const Float4& _b) {
return Float4(_a.x + _b.x, _a.y + _b.y, _a.z + _b.z, _a.w + _b.w);
}
OZZ_INLINE Float3 operator+(const Float3& _a, const Float3& _b) {
return Float3(_a.x + _b.x, _a.y + _b.y, _a.z + _b.z);
}
OZZ_INLINE Float2 operator+(const Float2& _a, const Float2& _b) {
return Float2(_a.x + _b.x, _a.y + _b.y);
}
// Returns per element subtraction of _a and _b using operator -.
OZZ_INLINE Float4 operator-(const Float4& _a, const Float4& _b) {
return Float4(_a.x - _b.x, _a.y - _b.y, _a.z - _b.z, _a.w - _b.w);
}
OZZ_INLINE Float3 operator-(const Float3& _a, const Float3& _b) {
return Float3(_a.x - _b.x, _a.y - _b.y, _a.z - _b.z);
}
OZZ_INLINE Float2 operator-(const Float2& _a, const Float2& _b) {
return Float2(_a.x - _b.x, _a.y - _b.y);
}
// Returns per element negative value of _v.
OZZ_INLINE Float4 operator-(const Float4& _v) {
return Float4(-_v.x, -_v.y, -_v.z, -_v.w);
}
OZZ_INLINE Float3 operator-(const Float3& _v) {
return Float3(-_v.x, -_v.y, -_v.z);
}
OZZ_INLINE Float2 operator-(const Float2& _v) { return Float2(-_v.x, -_v.y); }
// Returns per element multiplication of _a and _b using operator *.
OZZ_INLINE Float4 operator*(const Float4& _a, const Float4& _b) {
return Float4(_a.x * _b.x, _a.y * _b.y, _a.z * _b.z, _a.w * _b.w);
}
OZZ_INLINE Float3 operator*(const Float3& _a, const Float3& _b) {
return Float3(_a.x * _b.x, _a.y * _b.y, _a.z * _b.z);
}
OZZ_INLINE Float2 operator*(const Float2& _a, const Float2& _b) {
return Float2(_a.x * _b.x, _a.y * _b.y);
}
// Returns per element multiplication of _a and scalar value _f using
// operator *.
OZZ_INLINE Float4 operator*(const Float4& _a, float _f) {
return Float4(_a.x * _f, _a.y * _f, _a.z * _f, _a.w * _f);
}
OZZ_INLINE Float3 operator*(const Float3& _a, float _f) {
return Float3(_a.x * _f, _a.y * _f, _a.z * _f);
}
OZZ_INLINE Float2 operator*(const Float2& _a, float _f) {
return Float2(_a.x * _f, _a.y * _f);
}
// Returns per element division of _a and _b using operator /.
OZZ_INLINE Float4 operator/(const Float4& _a, const Float4& _b) {
return Float4(_a.x / _b.x, _a.y / _b.y, _a.z / _b.z, _a.w / _b.w);
}
OZZ_INLINE Float3 operator/(const Float3& _a, const Float3& _b) {
return Float3(_a.x / _b.x, _a.y / _b.y, _a.z / _b.z);
}
OZZ_INLINE Float2 operator/(const Float2& _a, const Float2& _b) {
return Float2(_a.x / _b.x, _a.y / _b.y);
}
// Returns per element division of _a and scalar value _f using operator/.
OZZ_INLINE Float4 operator/(const Float4& _a, float _f) {
return Float4(_a.x / _f, _a.y / _f, _a.z / _f, _a.w / _f);
}
OZZ_INLINE Float3 operator/(const Float3& _a, float _f) {
return Float3(_a.x / _f, _a.y / _f, _a.z / _f);
}
OZZ_INLINE Float2 operator/(const Float2& _a, float _f) {
return Float2(_a.x / _f, _a.y / _f);
}
// Returns the (horizontal) addition of each element of _v.
OZZ_INLINE float HAdd(const Float4& _v) { return _v.x + _v.y + _v.z + _v.w; }
OZZ_INLINE float HAdd(const Float3& _v) { return _v.x + _v.y + _v.z; }
OZZ_INLINE float HAdd(const Float2& _v) { return _v.x + _v.y; }
// Returns the dot product of _a and _b.
OZZ_INLINE float Dot(const Float4& _a, const Float4& _b) {
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
}
OZZ_INLINE float Dot(const Float3& _a, const Float3& _b) {
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z;
}
OZZ_INLINE float Dot(const Float2& _a, const Float2& _b) {
return _a.x * _b.x + _a.y * _b.y;
}
// Returns the cross product of _a and _b.
OZZ_INLINE Float3 Cross(const Float3& _a, const Float3& _b) {
return Float3(_a.y * _b.z - _b.y * _a.z, _a.z * _b.x - _b.z * _a.x,
_a.x * _b.y - _b.x * _a.y);
}
// Returns the length |_v| of _v.
OZZ_INLINE float Length(const Float4& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
return std::sqrt(len2);
}
OZZ_INLINE float Length(const Float3& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
return std::sqrt(len2);
}
OZZ_INLINE float Length(const Float2& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y;
return std::sqrt(len2);
}
// Returns the square length |_v|^2 of _v.
OZZ_INLINE float LengthSqr(const Float4& _v) {
return _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
}
OZZ_INLINE float LengthSqr(const Float3& _v) {
return _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
}
OZZ_INLINE float LengthSqr(const Float2& _v) {
return _v.x * _v.x + _v.y * _v.y;
}
// Returns the normalized vector _v.
OZZ_INLINE Float4 Normalize(const Float4& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
assert(len2 != 0.f && "_v is not normalizable");
const float len = std::sqrt(len2);
return Float4(_v.x / len, _v.y / len, _v.z / len, _v.w / len);
}
OZZ_INLINE Float3 Normalize(const Float3& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
assert(len2 != 0.f && "_v is not normalizable");
const float len = std::sqrt(len2);
return Float3(_v.x / len, _v.y / len, _v.z / len);
}
OZZ_INLINE Float2 Normalize(const Float2& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y;
assert(len2 != 0.f && "_v is not normalizable");
const float len = std::sqrt(len2);
return Float2(_v.x / len, _v.y / len);
}
// Returns true if _v is normalized.
OZZ_INLINE bool IsNormalized(const Float4& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
return std::abs(len2 - 1.f) < kNormalizationToleranceSq;
}
OZZ_INLINE bool IsNormalized(const Float3& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
return std::abs(len2 - 1.f) < kNormalizationToleranceSq;
}
OZZ_INLINE bool IsNormalized(const Float2& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y;
return std::abs(len2 - 1.f) < kNormalizationToleranceSq;
}
// Returns the normalized vector _v if the norm of _v is not 0.
// Otherwise returns _safer.
OZZ_INLINE Float4 NormalizeSafe(const Float4& _v, const Float4& _safer) {
assert(IsNormalized(_safer) && "_safer is not normalized");
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
if (len2 <= 0.f) {
return _safer;
}
const float len = std::sqrt(len2);
return Float4(_v.x / len, _v.y / len, _v.z / len, _v.w / len);
}
OZZ_INLINE Float3 NormalizeSafe(const Float3& _v, const Float3& _safer) {
assert(IsNormalized(_safer) && "_safer is not normalized");
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
if (len2 <= 0.f) {
return _safer;
}
const float len = std::sqrt(len2);
return Float3(_v.x / len, _v.y / len, _v.z / len);
}
OZZ_INLINE Float2 NormalizeSafe(const Float2& _v, const Float2& _safer) {
assert(IsNormalized(_safer) && "_safer is not normalized");
const float len2 = _v.x * _v.x + _v.y * _v.y;
if (len2 <= 0.f) {
return _safer;
}
const float len = std::sqrt(len2);
return Float2(_v.x / len, _v.y / len);
}
// Returns the linear interpolation of _a and _b with coefficient _f.
// _f is not limited to range [0,1].
OZZ_INLINE Float4 Lerp(const Float4& _a, const Float4& _b, float _f) {
return Float4((_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w);
}
OZZ_INLINE Float3 Lerp(const Float3& _a, const Float3& _b, float _f) {
return Float3((_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z);
}
OZZ_INLINE Float2 Lerp(const Float2& _a, const Float2& _b, float _f) {
return Float2((_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y);
}
// Returns true if the distance between _a and _b is less than _tolerance.
OZZ_INLINE bool Compare(const Float4& _a, const Float4& _b, float _tolerance) {
const math::Float4 diff = _a - _b;
return Dot(diff, diff) <= _tolerance * _tolerance;
}
OZZ_INLINE bool Compare(const Float3& _a, const Float3& _b, float _tolerance) {
const math::Float3 diff = _a - _b;
return Dot(diff, diff) <= _tolerance * _tolerance;
}
OZZ_INLINE bool Compare(const Float2& _a, const Float2& _b, float _tolerance) {
const math::Float2 diff = _a - _b;
return Dot(diff, diff) <= _tolerance * _tolerance;
}
// Returns true if each element of a is less than each element of _b.
OZZ_INLINE bool operator<(const Float4& _a, const Float4& _b) {
return _a.x < _b.x && _a.y < _b.y && _a.z < _b.z && _a.w < _b.w;
}
OZZ_INLINE bool operator<(const Float3& _a, const Float3& _b) {
return _a.x < _b.x && _a.y < _b.y && _a.z < _b.z;
}
OZZ_INLINE bool operator<(const Float2& _a, const Float2& _b) {
return _a.x < _b.x && _a.y < _b.y;
}
// Returns true if each element of a is less or equal to each element of _b.
OZZ_INLINE bool operator<=(const Float4& _a, const Float4& _b) {
return _a.x <= _b.x && _a.y <= _b.y && _a.z <= _b.z && _a.w <= _b.w;
}
OZZ_INLINE bool operator<=(const Float3& _a, const Float3& _b) {
return _a.x <= _b.x && _a.y <= _b.y && _a.z <= _b.z;
}
OZZ_INLINE bool operator<=(const Float2& _a, const Float2& _b) {
return _a.x <= _b.x && _a.y <= _b.y;
}
// Returns true if each element of a is greater than each element of _b.
OZZ_INLINE bool operator>(const Float4& _a, const Float4& _b) {
return _a.x > _b.x && _a.y > _b.y && _a.z > _b.z && _a.w > _b.w;
}
OZZ_INLINE bool operator>(const Float3& _a, const Float3& _b) {
return _a.x > _b.x && _a.y > _b.y && _a.z > _b.z;
}
OZZ_INLINE bool operator>(const Float2& _a, const Float2& _b) {
return _a.x > _b.x && _a.y > _b.y;
}
// Returns true if each element of a is greater or equal to each element of _b.
OZZ_INLINE bool operator>=(const Float4& _a, const Float4& _b) {
return _a.x >= _b.x && _a.y >= _b.y && _a.z >= _b.z && _a.w >= _b.w;
}
OZZ_INLINE bool operator>=(const Float3& _a, const Float3& _b) {
return _a.x >= _b.x && _a.y >= _b.y && _a.z >= _b.z;
}
OZZ_INLINE bool operator>=(const Float2& _a, const Float2& _b) {
return _a.x >= _b.x && _a.y >= _b.y;
}
// Returns true if each element of a is equal to each element of _b.
// Uses a bitwise comparison of _a and _b, no tolerance is applied.
OZZ_INLINE bool operator==(const Float4& _a, const Float4& _b) {
return _a.x == _b.x && _a.y == _b.y && _a.z == _b.z && _a.w == _b.w;
}
OZZ_INLINE bool operator==(const Float3& _a, const Float3& _b) {
return _a.x == _b.x && _a.y == _b.y && _a.z == _b.z;
}
OZZ_INLINE bool operator==(const Float2& _a, const Float2& _b) {
return _a.x == _b.x && _a.y == _b.y;
}
// Returns true if each element of a is different from each element of _b.
// Uses a bitwise comparison of _a and _b, no tolerance is applied.
OZZ_INLINE bool operator!=(const Float4& _a, const Float4& _b) {
return _a.x != _b.x || _a.y != _b.y || _a.z != _b.z || _a.w != _b.w;
}
OZZ_INLINE bool operator!=(const Float3& _a, const Float3& _b) {
return _a.x != _b.x || _a.y != _b.y || _a.z != _b.z;
}
OZZ_INLINE bool operator!=(const Float2& _a, const Float2& _b) {
return _a.x != _b.x || _a.y != _b.y;
}
// Returns the minimum of each element of _a and _b.
OZZ_INLINE Float4 Min(const Float4& _a, const Float4& _b) {
return Float4(_a.x < _b.x ? _a.x : _b.x, _a.y < _b.y ? _a.y : _b.y,
_a.z < _b.z ? _a.z : _b.z, _a.w < _b.w ? _a.w : _b.w);
}
OZZ_INLINE Float3 Min(const Float3& _a, const Float3& _b) {
return Float3(_a.x < _b.x ? _a.x : _b.x, _a.y < _b.y ? _a.y : _b.y,
_a.z < _b.z ? _a.z : _b.z);
}
OZZ_INLINE Float2 Min(const Float2& _a, const Float2& _b) {
return Float2(_a.x < _b.x ? _a.x : _b.x, _a.y < _b.y ? _a.y : _b.y);
}
// Returns the maximum of each element of _a and _b.
OZZ_INLINE Float4 Max(const Float4& _a, const Float4& _b) {
return Float4(_a.x > _b.x ? _a.x : _b.x, _a.y > _b.y ? _a.y : _b.y,
_a.z > _b.z ? _a.z : _b.z, _a.w > _b.w ? _a.w : _b.w);
}
OZZ_INLINE Float3 Max(const Float3& _a, const Float3& _b) {
return Float3(_a.x > _b.x ? _a.x : _b.x, _a.y > _b.y ? _a.y : _b.y,
_a.z > _b.z ? _a.z : _b.z);
}
OZZ_INLINE Float2 Max(const Float2& _a, const Float2& _b) {
return Float2(_a.x > _b.x ? _a.x : _b.x, _a.y > _b.y ? _a.y : _b.y);
}
// Clamps each element of _x between _a and _b.
// _a must be less or equal to b;
OZZ_INLINE Float4 Clamp(const Float4& _a, const Float4& _v, const Float4& _b) {
const Float4 min(_v.x < _b.x ? _v.x : _b.x, _v.y < _b.y ? _v.y : _b.y,
_v.z < _b.z ? _v.z : _b.z, _v.w < _b.w ? _v.w : _b.w);
return Float4(_a.x > min.x ? _a.x : min.x, _a.y > min.y ? _a.y : min.y,
_a.z > min.z ? _a.z : min.z, _a.w > min.w ? _a.w : min.w);
}
OZZ_INLINE Float3 Clamp(const Float3& _a, const Float3& _v, const Float3& _b) {
const Float3 min(_v.x < _b.x ? _v.x : _b.x, _v.y < _b.y ? _v.y : _b.y,
_v.z < _b.z ? _v.z : _b.z);
return Float3(_a.x > min.x ? _a.x : min.x, _a.y > min.y ? _a.y : min.y,
_a.z > min.z ? _a.z : min.z);
}
OZZ_INLINE Float2 Clamp(const Float2& _a, const Float2& _v, const Float2& _b) {
const Float2 min(_v.x < _b.x ? _v.x : _b.x, _v.y < _b.y ? _v.y : _b.y);
return Float2(_a.x > min.x ? _a.x : min.x, _a.y > min.y ? _a.y : min.y);
}
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_VEC_FLOAT_H_
@@ -0,0 +1,99 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MEMORY_ALLOCATOR_H_
#define OZZ_OZZ_BASE_MEMORY_ALLOCATOR_H_
#include <cstddef>
#include <new>
#include <utility>
#include "ozz/base/platform.h"
namespace ozz {
namespace memory {
// Forwards declare Allocator class.
class Allocator;
// Defines the default allocator accessor.
Allocator* default_allocator();
// Set the default allocator, used for all dynamic allocation inside ozz.
// Returns current memory allocator, such that in can be restored if needed.
Allocator* SetDefaulAllocator(Allocator* _allocator);
// Defines an abstract allocator class.
// Implements helper methods to allocate/deallocate POD typed objects instead of
// raw memory.
// Implements New and Delete function to allocate C++ objects, as a replacement
// of new and delete operators.
class Allocator {
public:
// Default virtual destructor.
virtual ~Allocator() {}
// Next functions are the pure virtual functions that must be implemented by
// allocator concrete classes.
// Allocates _size bytes on the specified _alignment boundaries.
// Allocate function conforms with standard malloc function specifications.
virtual void* Allocate(size_t _size, size_t _alignment) = 0;
// Frees a block that was allocated with Allocate or Reallocate.
// Argument _block can be nullptr.
// Deallocate function conforms with standard free function specifications.
virtual void Deallocate(void* _block) = 0;
};
} // namespace memory
// ozz replacement for c++ operator new with, used to allocate with an
// ozz::memory::Allocator. Delete must be used to deallocate such object.
// It can be used for constructor with no argument:
// Type* object = New<Type>();
// or any number of argument:
// Type* object = New<Type>(1,2,3,4);
template <typename _Ty, typename... _Args>
_Ty* New(_Args&&... _args) {
void* alloc =
memory::default_allocator()->Allocate(sizeof(_Ty), alignof(_Ty));
return new (alloc) _Ty(std::forward<_Args>(_args)...);
}
template <typename _Ty>
void Delete(_Ty* _object) {
if (_object) {
// Prevents from false "unreferenced parameter" warning when _Ty has no
// explicit destructor.
(void)_object;
_object->~_Ty();
memory::default_allocator()->Deallocate(_object);
}
}
} // namespace ozz
#endif // OZZ_OZZ_BASE_MEMORY_ALLOCATOR_H_
@@ -0,0 +1,61 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MEMORY_UNIQUE_PTR_H_
#define OZZ_OZZ_BASE_MEMORY_UNIQUE_PTR_H_
#include "ozz/base/memory/allocator.h"
#include <memory>
#include <utility>
namespace ozz {
// Defaut deleter for ozz unique_ptr, uses redirected memory allocator.
template <typename _Ty>
struct Deleter {
Deleter() {}
template <class _Up>
Deleter(const Deleter<_Up>&, _Ty* = nullptr) {}
void operator()(_Ty* _ptr) const {
ozz::Delete(_ptr);
}
};
// Defines ozz::unique_ptr to use ozz default deleter.
template <typename _Ty, typename _Deleter = ozz::Deleter<_Ty>>
using unique_ptr = std::unique_ptr<_Ty, _Deleter>;
// Implements make_unique to use ozz redirected memory allocator.
template <typename _Ty, typename... _Args>
unique_ptr<_Ty> make_unique(_Args&&... _args) {
return unique_ptr<_Ty>(New<_Ty>(std::forward<_Args>(_args)...));
}
} // namespace ozz
#endif // OZZ_OZZ_BASE_MEMORY_UNIQUE_PTR_H_
+114
View File
@@ -0,0 +1,114 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_PLATFORM_H_
#define OZZ_OZZ_BASE_PLATFORM_H_
// Ensures compiler supports c++11 language standards, to help user understand
// compilation error in case it's not supported.
// Unfortunately MSVC doesn't update __cplusplus, so test compiler version
// instead.
#if !((__cplusplus >= 201103L) || (_MSC_VER >= 1900))
#error "ozz-animation requires c++11 language standards."
#endif // __cplusplus
#include <stdint.h>
#include <cassert>
#include <cstddef>
namespace ozz {
// Finds the number of elements of a statically allocated array.
#define OZZ_ARRAY_SIZE(_array) (sizeof(_array) / sizeof(_array[0]))
// Instructs the compiler to try to inline a function, regardless cost/benefit
// compiler analysis.
// Syntax is: "OZZ_INLINE void function();"
#if defined(_MSC_VER)
#define OZZ_INLINE __forceinline
#else
#define OZZ_INLINE inline __attribute__((always_inline))
#endif
// Tells the compiler to never inline a function.
// Syntax is: "OZZ_NO_INLINE void function();"
#if defined(_MSC_VER)
#define OZZ_NOINLINE __declspec(noinline)
#else
#define OZZ_NOINLINE __attribute__((noinline))
#endif
// Tells the compiler that the memory addressed by the restrict -qualified
// pointer is not aliased, aka no other pointer will access that same memory.
// Syntax is: void function(int* OZZ_RESTRICT _p);"
#define OZZ_RESTRICT __restrict
// Defines macro to help with DEBUG/NDEBUG syntax.
#if defined(NDEBUG)
#define OZZ_IF_DEBUG(...)
#define OZZ_IF_NDEBUG(...) __VA_ARGS__
#else // NDEBUG
#define OZZ_IF_DEBUG(...) __VA_ARGS__
#define OZZ_IF_NDEBUG(...)
#endif // NDEBUG
// Case sensitive wildcard string matching:
// - a ? sign matches any character, except an empty string.
// - a * sign matches any string, including an empty string.
bool strmatch(const char* _str, const char* _pattern);
// Tests whether _block is aligned to _alignment boundary.
template <typename _Ty>
OZZ_INLINE bool IsAligned(_Ty _value, size_t _alignment) {
return (_value & (_alignment - 1)) == 0;
}
template <typename _Ty>
OZZ_INLINE bool IsAligned(_Ty* _address, size_t _alignment) {
return (reinterpret_cast<uintptr_t>(_address) & (_alignment - 1)) == 0;
}
// Aligns _block address to the first greater address that is aligned to
// _alignment boundaries.
template <typename _Ty>
OZZ_INLINE _Ty Align(_Ty _value, size_t _alignment) {
return static_cast<_Ty>(_value + (_alignment - 1)) & (0 - _alignment);
}
template <typename _Ty>
OZZ_INLINE _Ty* Align(_Ty* _address, size_t _alignment) {
return reinterpret_cast<_Ty*>(
(reinterpret_cast<uintptr_t>(_address) + (_alignment - 1)) &
(0 - _alignment));
}
// Offset a pointer from a given number of bytes.
template <typename _Ty>
_Ty* PointerStride(_Ty* _ty, size_t _stride) {
return reinterpret_cast<_Ty*>(reinterpret_cast<uintptr_t>(_ty) + _stride);
}
} // namespace ozz
#endif // OZZ_OZZ_BASE_PLATFORM_H_
+171
View File
@@ -0,0 +1,171 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_SPAN_H_
#define OZZ_OZZ_BASE_SPAN_H_
#include "ozz/base/platform.h"
namespace ozz {
// Defines a range [begin,end[ of objects ot type _Ty.
template <typename _Ty>
struct span {
// Constants and types
using element_type = _Ty;
using value_type = _Ty;
using index_type = size_t;
using difference_type = ptrdiff_t;
using pointer = _Ty*;
using const_pointer = const _Ty*;
using reference = _Ty&;
using const_reference = const _Ty&;
// Iterators
using iterator = pointer;
using const_iterator = const_pointer;
// Default constructor initializes range to empty.
span() : data_(nullptr), size_(0) {}
// Constructs a range from its extreme values.
span(_Ty* _begin, _Ty* _end) : data_(_begin), size_(static_cast<size_t>(_end - _begin)) {
assert(_begin <= _end && "Invalid range.");
}
// Construct a range from a pointer to a buffer and its size, ie its number of
// elements.
span(_Ty* _begin, size_t _size) : data_(_begin), size_(_size) {}
// Copy operator.
void operator=(const span& _other) {
data_ = _other.data_;
size_ = _other.size_;
}
// Construct a range from a single element.
explicit span(_Ty& _element) : data_(&_element), size_(1) {}
// Construct a range from an array, its size is automatically deduced.
// It isn't declared explicit as conversion is free and safe.
template <size_t _size>
span(_Ty (&_array)[_size]) : data_(_array), size_(_size) {}
// Reinitialized from an array, its size is automatically deduced.
template <size_t _size>
void operator=(_Ty (&_array)[_size]) {
data_ = _array;
size_ = _size;
}
// Implement cast operator to allow conversions to span<const _Ty>.
operator span<const _Ty>() const { return span<const _Ty>(data_, size_); }
// Returns a const reference to element _i of range [begin,end[.
_Ty& operator[](size_t _i) const {
assert(_i < size_ && "Index out of range.");
return data_[_i];
}
bool empty() const { return size_ == 0; }
// Complies with other contiguous containers.
_Ty* data() const { return data_; }
// Gets the number of elements of the range.
// This size isn't stored but computed from begin and end pointers.
size_t size() const { return size_; }
// Gets the size in byte of the range.
size_t size_bytes() const { return size_ * sizeof(element_type); }
// Iterator support
iterator begin() const { return data_; }
iterator end() const { return data_ + size_; }
private:
// span begin pointer.
_Ty* data_;
// span end pointer, should never be dereferenced.
size_t size_;
};
// Returns a span from an array.
template <typename _Ty, size_t _Size>
inline span<_Ty> make_span(_Ty (&_arr)[_Size]) {
return {_arr};
}
// Returns a mutable span from a container.
template <typename _Container>
inline span<typename _Container::value_type> make_span(_Container& _container) {
return {_container.data(), _container.size()};
}
// Returns a non mutable span from a container.
template <typename _Container>
inline span<const typename _Container::value_type> make_span(
const _Container& _container) {
return {_container.data(), _container.size()};
}
// As bytes
template <typename _Ty>
inline span<const char> as_bytes(const span<_Ty>& _span) {
return {reinterpret_cast<const char*>(_span.data()), _span.size_bytes()};
}
template <typename _Ty>
inline span<char> as_writable_bytes(const span<_Ty>& _span) {
// Compilation will fail here if _Ty is const. This prevents from writing to
// const data.
return {reinterpret_cast<char*>(_span.data()), _span.size_bytes()};
}
template <>
inline span<const char> as_bytes(const span<char>& _span) {
return _span;
}
template <>
inline span<char> as_writable_bytes(const span<char>& _span) {
return _span;
}
// Fills a typed span from a byte source span. Source byte span is modified to
// reflect remain size.
template <typename _Ty>
inline span<_Ty> fill_span(span<char>& _src, size_t _count) {
assert(ozz::IsAligned(_src.data(), alignof(_Ty)) && "Invalid alignment.");
const span<_Ty> ret = {reinterpret_cast<_Ty*>(_src.data()), _count};
// Validity assertion is done by span constructor.
_src = {reinterpret_cast<char*>(ret.end()), _src.end()};
return ret;
}
} // namespace ozz
#endif // OZZ_OZZ_BASE_SPAN_H_