Browse Source

Adding ik library to Urho3D thirdparty libs

TheComet 8 years ago
parent
commit
d2911ad455
36 changed files with 5280 additions and 0 deletions
  1. 59 0
      Source/ThirdParty/ik/CMakeLists.txt
  2. 21 0
      Source/ThirdParty/ik/LICENSE
  3. 105 0
      Source/ThirdParty/ik/README.md
  4. 95 0
      Source/ThirdParty/ik/cmake/Urho3D/CMakeLists.txt
  5. 121 0
      Source/ThirdParty/ik/cmake/templates/VisualStudioUserFile.vcproj.user.in
  6. 23 0
      Source/ThirdParty/ik/cmake/templates/VisualStudioUserFile.vcxproj.user.in
  7. 90 0
      Source/ThirdParty/ik/ik/CMakeLists.txt
  8. 1 0
      Source/ThirdParty/ik/ik/include/ik/.gitignore
  9. 22 0
      Source/ThirdParty/ik/ik/include/ik/backtrace.h
  10. 227 0
      Source/ThirdParty/ik/ik/include/ik/bst_vector.h
  11. 27 0
      Source/ThirdParty/ik/ik/include/ik/config.h.in
  12. 106 0
      Source/ThirdParty/ik/ik/include/ik/effector.h
  13. 120 0
      Source/ThirdParty/ik/ik/include/ik/export.h.in
  14. 8 0
      Source/ThirdParty/ik/ik/include/ik/ik.h
  15. 33 0
      Source/ThirdParty/ik/ik/include/ik/log.h
  16. 58 0
      Source/ThirdParty/ik/ik/include/ik/memory.h
  17. 176 0
      Source/ThirdParty/ik/ik/include/ik/node.h
  18. 297 0
      Source/ThirdParty/ik/ik/include/ik/ordered_vector.h
  19. 813 0
      Source/ThirdParty/ik/ik/include/ik/pstdint.h
  20. 101 0
      Source/ThirdParty/ik/ik/include/ik/quat.h
  21. 227 0
      Source/ThirdParty/ik/ik/include/ik/solver.h
  22. 39 0
      Source/ThirdParty/ik/ik/include/ik/solver_FABRIK.h
  23. 13 0
      Source/ThirdParty/ik/ik/include/ik/solver_jacobian_inverse.h
  24. 13 0
      Source/ThirdParty/ik/ik/include/ik/solver_jacobian_transpose.h
  25. 50 0
      Source/ThirdParty/ik/ik/include/ik/vec3.h
  26. 253 0
      Source/ThirdParty/ik/ik/src/bst_vector.c
  27. 44 0
      Source/ThirdParty/ik/ik/src/effector.c
  28. 97 0
      Source/ThirdParty/ik/ik/src/log.c
  29. 281 0
      Source/ThirdParty/ik/ik/src/memory.c
  30. 160 0
      Source/ThirdParty/ik/ik/src/node.c
  31. 351 0
      Source/ThirdParty/ik/ik/src/ordered_vector.c
  32. 15 0
      Source/ThirdParty/ik/ik/src/platform/linux/backtrace_linux.c
  33. 147 0
      Source/ThirdParty/ik/ik/src/quat.c
  34. 181 0
      Source/ThirdParty/ik/ik/src/solver.c
  35. 814 0
      Source/ThirdParty/ik/ik/src/solver_FABRIK.c
  36. 92 0
      Source/ThirdParty/ik/ik/src/vec3.c

+ 59 - 0
Source/ThirdParty/ik/CMakeLists.txt

@@ -0,0 +1,59 @@
+cmake_minimum_required (VERSION 2.6)
+
+# If the user specifies -DCMAKE_BUILD_TYPE on the command line, take their
+# definition and dump it in the cache along with proper documentation, otherwise
+# set MAKE_BUILD_TYPE to Debug prior to calling PROJECT()
+if (DEFINED CMAKE_BUILD_TYPE)
+    set (CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
+else()
+    set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
+endif()
+message (STATUS "Build type: ${CMAKE_BUILD_TYPE}")
+
+###############################################################################
+# Project name
+###############################################################################
+
+project ("ik" C)
+
+# Make macs happy
+set (CMAKE_MACOSX_RPATH OFF)
+
+###############################################################################
+# compiler definitions and flags
+###############################################################################
+
+if (${CMAKE_C_COMPILER_ID} STREQUAL "GNU")
+    add_definitions (-W -Wall -fno-omit-frame-pointer)
+elseif (${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
+    add_definitions (-W -Wall -fno-omit-frame-pointer)
+elseif (${CMAKE_C_COMPILER_ID} STREQUAL "Intel")
+elseif (${CMAKE_C_COMPILER_ID} STREQUAL "MSVC")
+    add_definitions (-D_CRT_SECURE_NO_WARNINGS)
+    if (CMAKE_BUILD_TYPE MATCHES Debug)
+        STRING(REGEX REPLACE "/MDd" "" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
+        add_definitions (-MTd)
+    elseif (CMAKE_BUILD_TYPE MATCHES Release)
+        STRING(REGEX REPLACE "/MD" "" CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE})
+        add_definitions (-MT)
+    endif ()
+endif ()
+
+if (CMAKE_BUILD_TYPE MATCHES Debug)
+    add_definitions(-DDEBUG)
+endif ()
+
+###############################################################################
+# Dependency settings
+###############################################################################
+
+message (STATUS "------------------------------------------------------------")
+message (STATUS "Global settings")
+message (STATUS "------------------------------------------------------------")
+
+add_subdirectory ("ik")
+
+option (IK_TESTS "Whether to build unit tests or not (requires C++)" OFF)
+if (IK_TESTS)
+    add_subdirectory ("tests")
+endif ()

+ 21 - 0
Source/ThirdParty/ik/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Alex Murray.
+
+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.

+ 105 - 0
Source/ThirdParty/ik/README.md

@@ -0,0 +1,105 @@
+Inverse Kinematics Library
+==========================
+
+Very much a work-in-progress. In its current state, this library  is  not  yet
+usable. Please come back later :)
+
+The  goal  of  this  library is to provide a fast,  lightweight  and  flexible
+solution to solving the inverse kinematics problem.
+
+Overview
+--------
+
+One of the challenges was to design an interface  which  could  work  with any
+scene graph/skeleton/animation system.  The  library  provides  a leightweight
+interface for building a tree  and specifying positions and rotations for each
+node.  The tree also holds information on effector targets and  chain  length.
+The  tree is then preprocessed into a more optimal form for the  solver.  This
+preprocessing step is necessary  whenever the tree is altered or effectors are
+added or removed,  which,  in  practice,  should only occur once. Invoking the
+solver  will  cause  a  series  of  computations  to  occur  on  the  internal
+structures, the results of which will then be  mapped  back  onto the original
+tree structure specified by the user. The user can then iterate  the  tree and
+apply   the   solved   positions   and   rotations   back   to    his    scene
+graph/skeleton/animation structure.
+
+All  of the code was written in C89 and has no dependencies other than  the  C
+standard  library.  Memory  debugging  facilities are in place to track memory
+leaks.  On  linux,  backtraces can be generated to the respective malloc() and
+free() calls.
+
+Example usage
+-------------
+
+Here is a minimal working example that probably satisfies your needs.
+
+```cpp
+#include <ik/ik.h>
+
+static void results_callback(struct ik_node_t* ikNode)
+{
+    /* Extract our scene graph node again */
+    Node* node = (Node)ikNode->user_data;
+
+    /* Apply results back to our engine's tree */
+    node->SetWorldPosition(ikNode->solved_position);
+    node->SetWorldRotation(ikNode->solved_rotation);
+}
+
+int main()
+{
+    /* Create a tree that splits into two arms */
+    struct node_t* root = node_create(0);
+    struct node_t* child1 = node_create(1);
+    struct node_t* child2 = node_create(2);
+    struct node_t* child3 = node_create(3);
+    struct node_t* child4 = node_create(4);
+    struct node_t* child5 = node_create(5);
+    struct node_t* child6 = node_create(6);
+    node_add_child(root, child1);
+    node_add_child(child1, child2);
+    node_add_child(child2, child3);
+    node_add_child(child3, child4);
+    node_add_child(child2, child5);
+    node_add_child(child5, child6);
+
+    /* Lets assume we are developing a game engine that has its own scene graph,
+     * and lets assume it has the same structure as the tree created above.
+     */
+    Node* sceneRoot = GetSceneRoot();
+
+    /* Store a pointer to each engine node to user_data so we can use it later */
+    root->user_data = sceneRoot;
+    child1->user_data = sceneRoot->GetChild(1);
+    child2->user_data = sceneRoot->GetChild(2);
+    child3->user_data = sceneRoot->GetChild(3);
+    child4->user_data = sceneRoot->GetChild(4);
+    child5->user_data = sceneRoot->GetChild(5);
+    child6->user_data = sceneRoot->GetChild(6);
+
+    /* Attach an effector on each arm */
+    struct effector_t* eff1 = effector_create();
+    struct effector_t* eff2 = effector_create();
+    node_attach_effector(child4, eff1);
+    node_attach_effector(child6, eff2);
+
+    /* Each arm is composed of 3 nodes (2 segments), and we only want to control
+     * that portion of the tree. */
+    eff1->chain_length = 2;
+    eff2->chain_length = 2;
+
+    /* Create a solver and set up the results callback function, which gets
+     * called once for every computed result. */
+    struct ik_solver_t* solver = ik_solver_create(SOLVER_FABRIK);
+    solver->apply_result = results_callback;
+
+    /* We want to calculate rotations as well as positions */
+    solver->flags |= SOLVER_CALCULATE_FINAL_ROTATIONS;
+
+    /* Assign our tree to the solver and rebuild the data */
+    ik_solver_set_tree(solver, root);
+    ik_solver_rebuild_data(solver);
+    ik_solver_solve(solver);
+}
+
+```

+ 95 - 0
Source/ThirdParty/ik/cmake/Urho3D/CMakeLists.txt

@@ -0,0 +1,95 @@
+# Copyright (c) 2008-2017 the Urho3D project.
+#
+# 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.
+#
+
+# memory debugging
+if (CMAKE_BUILD_TYPE MATCHES Debug)
+    option (IK_MEMORY_DEBUGGING "Global switch for memory options. Keeps track of the number of allocations and de-allocations and prints a report when the program shuts down" ON)
+else ()
+    option (IK_MEMORY_DEBUGGING "Global switch for memory options. Keeps track of the number of allocations and de-allocations and prints a report when the program shuts down" OFF)
+endif ()
+if (IK_MEMORY_DEBUGGING)
+    if(${CMAKE_BUILD_TYPE} MATCHES Debug)
+        option (IK_MEMORY_BACKTRACE "Generates backtraces for every malloc(), making it easy to track down memory leaks" ON)
+    else ()
+        option (IK_MEMORY_BACKTRACE "Generates backtraces for every malloc(), making it easy to track down memory leaks" OFF)
+    endif ()
+else ()
+    option (IK_MEMORY_BACKTRACE "Generates backtraces for every malloc(), making it easy to track down memory leaks" OFF)
+endif ()
+
+set (IK_REAL "float" CACHE STRING "Type to use for real numbers")
+option (IK_DOT_OUTPUT "When enabled, the generated chains are dumped to DOT for debug purposes" OFF)
+
+set (EXPORT_H_TEMPLATE )
+
+configure_file ("../../ik/include/ik/export.h.in"
+                "../../include/ik/gen/export.h")
+configure_file ("../../ik/include/ik/config.h.in"
+                "../../include/ik/gen/config.h")
+
+###############################################################################
+# compiler flags
+###############################################################################
+
+if (${CMAKE_C_COMPILER_ID} STREQUAL "GNU")
+    add_definitions (-W -Wall -Wextra -Werror -pedantic -Wno-unused-parameter -fno-math-errno -ffast-math)
+elseif (${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
+    add_definitions (-W -Wall -Wextra -Werror -pedantic -Wno-unused-parameter -fno-math-errno -ffast-math)
+elseif (${CMAKE_C_COMPILER_ID} STREQUAL "Intel")
+elseif (${CMAKE_C_COMPILER_ID} STREQUAL "MSVC")
+    add_definitions (-D_CRT_SECURE_NO_WARNINGS)
+    if (CMAKE_BUILD_TYPE MATCHES Debug)
+        STRING(REGEX REPLACE "/MDd" "" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
+        add_definitions (-MTd)
+    elseif (CMAKE_BUILD_TYPE MATCHES Release)
+        STRING(REGEX REPLACE "/MD" "" CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE})
+        add_definitions (-MT)
+    endif ()
+endif ()
+
+# The library is being built
+add_definitions (-DIK_BUILDING)
+
+###############################################################################
+# source files and library definition
+###############################################################################
+
+file (GLOB IK_HEADERS "../../ik/include/ik/*.h")
+file (GLOB IK_SOURCES "../../ik/src/*.c")
+
+if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+    file (GLOB IK_PLATFORM_SOURCES "../../ik/src/platform/linux/*.c")
+endif ()
+list (APPEND IK_SOURCES ${IK_PLATFORM_SOURCES})
+
+set (TARGET_NAME IK)
+set (SOURCE_FILES ${IK_SOURCES} ${IK_HEADERS})
+set (INCLUDE_DIRS ../../ik/include ${CMAKE_CURRENT_BINARY_DIR}/../../include)
+
+setup_library ()
+
+###############################################################################
+# install targets
+###############################################################################
+
+# Install headers for building and using the Urho3D library
+install_header_files (DIRECTORY ../../ik/include/ik/ DESTINATION ${DEST_INCLUDE_DIR}/ThirdParty/ik)
+install_header_files (DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../include/ik/gen/ DESTINATION ${DEST_INCLUDE_DIR}/ThirdParty/ik/gen)

+ 121 - 0
Source/ThirdParty/ik/cmake/templates/VisualStudioUserFile.vcproj.user.in

@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioUserFile
+	ProjectType="Visual C++"
+	Version="8.00"
+	ShowAllFiles="false"
+	>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			>
+			<DebugSettings
+				Command="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@/$(TargetFileName)"
+				WorkingDirectory="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@"
+				CommandArguments=""
+				Attach="false"
+				DebuggerType="3"
+				Remote="1"
+				RemoteMachine=""
+				RemoteCommand=""
+				HttpUrl=""
+				PDBPath=""
+				SQLDebugging=""
+				Environment=""
+				EnvironmentMerge="true"
+				DebuggerFlavor="0"
+				MPIRunCommand=""
+				MPIRunArguments=""
+				MPIRunWorkingDirectory=""
+				ApplicationCommand=""
+				ApplicationArguments=""
+				ShimCommand=""
+				MPIAcceptMode=""
+				MPIAcceptFilter=""
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			>
+			<DebugSettings
+				Command="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@/$(TargetFileName)"
+				WorkingDirectory="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@"
+				CommandArguments=""
+				Attach="false"
+				DebuggerType="3"
+				Remote="1"
+				RemoteMachine=""
+				RemoteCommand=""
+				HttpUrl=""
+				PDBPath=""
+				SQLDebugging=""
+				Environment=""
+				EnvironmentMerge="true"
+				DebuggerFlavor="0"
+				MPIRunCommand=""
+				MPIRunArguments=""
+				MPIRunWorkingDirectory=""
+				ApplicationCommand=""
+				ApplicationArguments=""
+				ShimCommand=""
+				MPIAcceptMode=""
+				MPIAcceptFilter=""
+			/>
+		</Configuration>
+		<Configuration
+			Name="RelWithDebInfo|Win32"
+			>
+			<DebugSettings
+				Command="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@/$(TargetFileName)"
+				WorkingDirectory="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@"
+				CommandArguments=""
+				Attach="false"
+				DebuggerType="3"
+				Remote="1"
+				RemoteMachine=""
+				RemoteCommand=""
+				HttpUrl=""
+				PDBPath=""
+				SQLDebugging=""
+				Environment=""
+				EnvironmentMerge="true"
+				DebuggerFlavor="0"
+				MPIRunCommand=""
+				MPIRunArguments=""
+				MPIRunWorkingDirectory=""
+				ApplicationCommand=""
+				ApplicationArguments=""
+				ShimCommand=""
+				MPIAcceptMode=""
+				MPIAcceptFilter=""
+			/>
+		</Configuration>
+		<Configuration
+			Name="MinSizeRel|Win32"
+			>
+			<DebugSettings
+				Command="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@/$(TargetFileName)"
+				WorkingDirectory="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@"
+				CommandArguments=""
+				Attach="false"
+				DebuggerType="3"
+				Remote="1"
+				RemoteMachine=""
+				RemoteCommand=""
+				HttpUrl=""
+				PDBPath=""
+				SQLDebugging=""
+				Environment=""
+				EnvironmentMerge="true"
+				DebuggerFlavor="0"
+				MPIRunCommand=""
+				MPIRunArguments=""
+				MPIRunWorkingDirectory=""
+				ApplicationCommand=""
+				ApplicationArguments=""
+				ShimCommand=""
+				MPIAcceptMode=""
+				MPIAcceptFilter=""
+			/>
+		</Configuration>
+	</Configurations>
+</VisualStudioUserFile>

+ 23 - 0
Source/ThirdParty/ik/cmake/templates/VisualStudioUserFile.vcxproj.user.in

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+	<LocalDebuggerCommand>$(TargetPath)</LocalDebuggerCommand>
+    <LocalDebuggerWorkingDirectory>@CMAKE_RUNTIME_OUTPUT_DIRECTORY@</LocalDebuggerWorkingDirectory>
+    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LocalDebuggerCommand>$(TargetPath)</LocalDebuggerCommand>
+    <LocalDebuggerWorkingDirectory>@CMAKE_RUNTIME_OUTPUT_DIRECTORY@</LocalDebuggerWorkingDirectory>
+	<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|Win32'">
+    <LocalDebuggerCommand>$(TargetPath)</LocalDebuggerCommand>
+    <LocalDebuggerWorkingDirectory>@CMAKE_RUNTIME_OUTPUT_DIRECTORYR@</LocalDebuggerWorkingDirectory>
+	<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|Win32'">
+    <LocalDebuggerCommand>$(TargetPath)</LocalDebuggerCommand>
+    <LocalDebuggerWorkingDirectory>@CMAKE_RUNTIME_OUTPUT_DIRECTORY@</LocalDebuggerWorkingDirectory>
+	<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+  </PropertyGroup>
+</Project>

+ 90 - 0
Source/ThirdParty/ik/ik/CMakeLists.txt

@@ -0,0 +1,90 @@
+set (PROJECT_NAME "IK")
+set (BUILD_TYPE "STATIC")
+
+# memory debugging
+if (CMAKE_BUILD_TYPE MATCHES Debug)
+    option (IK_MEMORY_DEBUGGING "Global switch for memory options. Keeps track of the number of allocations and de-allocations and prints a report when the program shuts down" ON)
+else ()
+    option (IK_MEMORY_DEBUGGING "Global switch for memory options. Keeps track of the number of allocations and de-allocations and prints a report when the program shuts down" OFF)
+endif ()
+if (IK_MEMORY_DEBUGGING)
+    if(${CMAKE_BUILD_TYPE} MATCHES Debug)
+        option (IK_MEMORY_BACKTRACE "Generates backtraces for every malloc(), making it easy to track down memory leaks" ON)
+    else ()
+        option (IK_MEMORY_BACKTRACE "Generates backtraces for every malloc(), making it easy to track down memory leaks" OFF)
+    endif ()
+else ()
+    option (IK_MEMORY_BACKTRACE "Generates backtraces for every malloc(), making it easy to track down memory leaks" OFF)
+endif ()
+
+set (IK_REAL "float" CACHE STRING "Type to use for real numbers")
+option (IK_DOT_OUTPUT "When enabled, the generated chains are dumped to DOT for debug purposes" OFF)
+
+configure_file ("include/ik/export.h.in"
+                "include/ik/gen/export.h")
+configure_file ("include/ik/config.h.in"
+                "include/ik/gen/config.h")
+
+include_directories ("${CMAKE_CURRENT_BINARY_DIR}/include")
+
+###############################################################################
+# compiler flags
+###############################################################################
+
+if (${CMAKE_C_COMPILER_ID} STREQUAL "GNU")
+    add_definitions (-W -Wall -Wextra -Werror -pedantic -Wno-unused-parameter -fno-math-errno -ffast-math)
+elseif (${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
+    add_definitions (-W -Wall -Wextra -Werror -pedantic -Wno-unused-parameter -fno-math-errno -ffast-math)
+elseif (${CMAKE_C_COMPILER_ID} STREQUAL "Intel")
+elseif (${CMAKE_C_COMPILER_ID} STREQUAL "MSVC")
+    add_definitions (-D_CRT_SECURE_NO_WARNINGS)
+    if (CMAKE_BUILD_TYPE MATCHES Debug)
+        STRING(REGEX REPLACE "/MDd" "" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
+        add_definitions (-MTd)
+    elseif (CMAKE_BUILD_TYPE MATCHES Release)
+        STRING(REGEX REPLACE "/MD" "" CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE})
+        add_definitions (-MT)
+    endif ()
+endif ()
+
+###############################################################################
+# source files and library definition
+###############################################################################
+
+file (GLOB IK_HEADERS "include/ik/*.h")
+file (GLOB IK_SOURCES "src/*.c")
+
+list (APPEND IK_HEADERS
+    "include/ik/config.h.in"
+    "include/ik/export.h.in")
+
+if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+    file (GLOB IK_PLATFORM_SOURCES "src/platform/linux/*.c")
+endif ()
+list (APPEND IK_SOURCES ${IK_PLATFORM_SOURCES})
+
+include_directories ("include")
+
+add_library (ik ${BUILD_TYPE}
+    ${IK_HEADERS}
+    ${IK_SOURCES}
+)
+
+# The library is being built
+add_definitions (-DIK_BUILDING)
+
+###############################################################################
+# install targets
+###############################################################################
+
+# only install if shared library
+if (${BUILD_TYPE} STREQUAL "SHARED")
+    install (
+        TARGETS
+            ik
+        LIBRARY DESTINATION
+            "lib"
+        RUNTIME DESTINATION
+            "bin"
+    )
+endif ()

+ 1 - 0
Source/ThirdParty/ik/ik/include/ik/.gitignore

@@ -0,0 +1 @@
+/gen

+ 22 - 0
Source/ThirdParty/ik/ik/include/ik/backtrace.h

@@ -0,0 +1,22 @@
+#ifndef LIGHTSHIP_UTIL_BACKTRACE_H
+#define LIGHTSHIP_UTIL_BACKTRACE_H
+
+#define BACKTRACE_SIZE 64
+
+#include "ik/gen/config.h"
+#include "ik/pstdint.h"
+
+C_HEADER_BEGIN
+
+/*!
+ * @brief Generates a backtrace.
+ * @param[in] size The maximum number of frames to walk.
+ * @return Returns an array of char* arrays.
+ * @note The returned array must be freed manually with FREE(returned_array).
+ */
+IK_PUBLIC_API char**
+get_backtrace(int* size);
+
+C_HEADER_END
+
+#endif /* LIGHTSHIP_UTIL_BACKTRACE_H */

+ 227 - 0
Source/ThirdParty/ik/ik/include/ik/bst_vector.h

@@ -0,0 +1,227 @@
+/*!
+ * @file bst_vector.h
+ * @brief Implements a container of ordered key-value pairs stored in a vector
+ * (ordered by key). The hash is computed from a key (string) provided by the
+ * user.
+ */
+
+#ifndef IK_BST_VECTOR_H
+#define IK_BST_VECTOR_H
+
+#include "ik/pstdint.h"
+#include "ik/gen/config.h"
+#include "ik/ordered_vector.h"
+
+C_HEADER_BEGIN
+
+struct bstv_hash_value_t
+{
+    uint32_t hash;
+    void*    value;
+};
+
+struct bstv_t
+{
+    struct ordered_vector_t   vector;
+};
+
+/*!
+ * @brief Creates a new bstv object.
+ * @return Returns the newly created bstv object. It must be freed with
+ * bstv_destroy() when no longer required.
+ */
+IK_PUBLIC_API struct bstv_t*
+bstv_create(void);
+
+/*!
+ * @brief Initialises an existing bstv object.
+ * @note This does **not** FREE existing elements. If you have elements in your
+ * bstv and call this, those elements will be lost and a memory leak will have
+ * been created.
+ * @param[in] bstv The bstv object to initialise.
+ */
+IK_PUBLIC_API void
+bstv_construct(struct bstv_t* bstv);
+
+/*!
+ * @brief Destroys an existing bstv object and FREEs the underlying memory.
+ * @note Elements inserted into the bstv are not FREEd.
+ * @param[in] bstv The bstv object to destroy.
+ */
+IK_PUBLIC_API void
+bstv_destroy(struct bstv_t* bstv);
+
+/*!
+ * @brief Inserts an element into the bstv using a hashed key.
+ *
+ * @warning There is no way to test for hash collisions since this function
+ * doesn't have access to the key which generated the hash. It is highly
+ * discouraged to mix bstv_insert_hash() and bstv_insert(). Use one or the other.
+ *
+ * @note Complexity is O(log2(n)) to find the insertion point.
+ *
+ * @param[in] bstv The bstv object to insert into.
+ * @param[in] hash A unique key to assign to the element being inserted. The
+ * key must not exist in the bstv, or the element will not be inserted.
+ * @param[in] value The data to insert into the bstv.
+ * @note The value is **not** copied into the bstv, only referenced. For this
+ * reason don't insert stack allocated items into the bstv.
+ * @return Returns 0 if insertion was successful. Returns 1 if the key already
+ * existed (in which case nothing is inserted). Returns -1 on failure.
+ */
+IK_PUBLIC_API int
+bstv_insert(struct bstv_t* bstv, uint32_t hash, void* value);
+
+/*!
+ * @brief Sets the value bstvped to the specified hash in the bstv.
+ * @note If the hash is not found, this function silently fails.
+ * @param[in] bstv A pointer to the bstv object to change the value of.
+ * @param[in] hash The unique key associated with the value you want to change.
+ * @param[in] value The new value to set.
+ */
+IK_PUBLIC_API void
+bstv_set(struct bstv_t* bstv, uint32_t hash, void* value);
+
+/*!
+ * @brief Looks for an element in the bstv and returns it if found.
+ * @note Complexity is O(log2(n)).
+ * @param[in] bstv The bstv to search in.
+ * @param[in] hash The hash to search for.
+ * @return Returns the data associated with the specified hash. If the hash is
+ * not found in the bstv, then NULL is returned.
+ * @note Potential pitfall: The value could be NULL even if the hash was found,
+ * as NULL is a valid thing for a value to be. If you are checking to see if a
+ * hash exists, use bstv_key_exists() instead.
+ */
+IK_PUBLIC_API void*
+bstv_find(const struct bstv_t* bstv, uint32_t hash);
+
+/*!
+ * @brief Looks for an element in the bstv and returns a pointer to the element
+ * in the structure. This is useful if you need to store data directly in the
+ * memory occupied by the pointer and wish to modify it.
+ * @note The returned pointer can be invalidated if any insertions or deletions
+ * are performed.
+ * @param[in] bstv The bstv to search in.
+ * @param[in] hash The has to search for.
+ */
+IK_PUBLIC_API void**
+bstv_find_ptr(const struct bstv_t* bstv, uint32_t hash);
+
+/*!
+ * @brief Finds the specified element in the bstv and returns its key.
+ * @note Complexity is O(n).
+ * @param[in] bstv The bstv to search.
+ * @param[in] value The value to search for.
+ * @return Returns the key if it was successfully found, or MAP_INVALID_KEY if
+ * otherwise.
+ */
+IK_PUBLIC_API uint32_t
+bstv_find_element(const struct bstv_t* bstv, const void* value);
+
+/*!
+ * @brief Gets any element from the bstv.
+ *
+ * This is useful when you want to iterate and remove all items from the bstv
+ * at the same time.
+ * @return Returns an element as a void pointer. Which element is random.
+ */
+IK_PUBLIC_API void*
+bstv_get_any_element(const struct bstv_t* bstv);
+
+/*!
+ * @brief Returns 1 if the specified hash exists, 0 if otherwise.
+ * @param bstv The bstv to find the hash in.
+ * @param hash The hash to search for.
+ * @return 0 if the hash was found, -1 if the hash was not found.
+ */
+IK_PUBLIC_API int
+bstv_hash_exists(struct bstv_t* bstv, uint32_t hash);
+
+/*!
+ * @brief Returns a hash that does not yet exist in the bstv.
+ * @note Complexity is O(n)
+ * @param[in] bstv The bstv to generate a hash from.
+ * @return Returns a hash that does not yet exist in the bstv.
+ */
+IK_PUBLIC_API uint32_t
+bstv_find_unused_hash(struct bstv_t* bstv);
+
+/*!
+ * @brief Erases an element from the bstv using a hash.
+ * @warning It is highly discouraged to mix bstv_erase_using_hash() and
+ * bstv_erase_using_key(). Use bstv_erase_using_hash() if you used
+ * bstv_insert_using_hash(). Use bstv_erase_using_key() if you used
+ * bstv_insert_using_key().
+ * @note Complexity is O(log2(n))
+ * @param[in] bstv The bstv to erase from.
+ * @param[in] hash The hash that bstvs to the element to remove from the bstv.
+ * @return Returns the data assocated with the specified hash. If the hash is
+ * not found in the bstv, NULL is returned.
+ * @note The bstv only holds references to values and does **not** FREE them. It
+ * is up to the programmer to correctly free the elements being erased from the
+ * bstv.
+ */
+IK_PUBLIC_API void*
+bstv_erase(struct bstv_t* bstv, uint32_t hash);
+
+IK_PUBLIC_API void*
+bstv_erase_element(struct bstv_t* bstv, void* value);
+
+/*!
+ * @brief Erases the entire bstv, including the underlying memory.
+ * @note This does **not** FREE existing elements. If you have elements in your
+ * bstv and call this, those elements will be lost and a memory leak will have
+ * been created.
+ * @param[in] bstv The bstv to clear.
+ */
+IK_PUBLIC_API void
+bstv_clear(struct bstv_t* bstv);
+
+IK_PUBLIC_API void
+bstv_clear_free(struct bstv_t* bstv);
+
+/*!
+ * @brief Returns the number of elements in the specified bstv.
+ * @param[in] bstv The bstv to count the elements of.
+ * @return The number of elements in the specified bstv.
+ */
+#define bstv_count(bstv) ((bstv)->vector.count)
+
+/*!
+ * @brief Iterates over the specified bstv's elements and opens a FOR_EACH
+ * scope.
+ * @param[in] bstv The bstv to iterate.
+ * @param[in] var_type The type of data being held in the bstv.
+ * @param[in] var The name to give the variable pointing to the current
+ * element.
+ */
+#define BSTV_FOR_EACH(bstv, var_t, hash_v, var_v) {                                                      \
+    uint32_t i_##var_v;                                                                                  \
+    uint32_t hash_v;                                                                                     \
+    var_t* var_v;                                                                                        \
+    for(i_##var_v = 0;                                                                                   \
+        i_##var_v != bstv_count(bstv) &&                                                                 \
+            ((hash_v = ((struct bstv_hash_value_t*) (bstv)->vector.data)[i_##var_v].hash) || 1) &&       \
+            ((var_v  = (var_t*)((struct bstv_hash_value_t*)(bstv)->vector.data)[i_##var_v].value) || 1); \
+        ++i_##var_v) {
+
+/*!
+ * @brief Closes a for each scope previously opened by BSTV_FOR_EACH.
+ */
+#define BSTV_END_EACH }}
+
+/*!
+ * @brief Will erase the current selected item in a for loop from the bstv.
+ * @note This does not free the data being referenced by the bstv. You will have
+ * to erase that manually (either before or after this operation, it doesn't
+ * matter).
+ * @param[in] bstv A pointer to the bstv object currently being iterated.
+ */
+#define BSTV_ERASE_CURRENT_ITEM_IN_FOR_LOOP(bstv, var_v) do { \
+    ordered_vector_erase_element(&(bstv)->vector, ((struct bstv_hash_value_t*)(bstv)->vector.data) + i_##var_v); \
+    --i_##var_v; } while(0)
+
+C_HEADER_END
+
+#endif /* IK_BST_VECTOR_H */

+ 27 - 0
Source/ThirdParty/ik/ik/include/ik/config.h.in

@@ -0,0 +1,27 @@
+/* --------------------------------------------------------------
+ * Configures prerequisits for this library
+ * --------------------------------------------------------------*/
+
+#ifndef IK_CONFIG_HPP
+#   define IK_CONFIG_HPP
+
+#   include "ik/gen/export.h"
+
+    /* --------------------------------------------------------------
+     * build settings
+     * --------------------------------------------------------------*/
+
+#   define OFF    0
+#   define ON     1
+#   define SHARED 2
+#   define STATIC 3
+
+#   define IK_BUILD_TYPE STATIC
+#   define ik_real @IK_REAL@
+#   define IK_MEMORY_DEBUGGING @IK_MEMORY_DEBUGGING@
+#   if IK_MEMORY_DEBUGGING == ON
+#       define IK_MEMORY_BACKTRACE @IK_MEMORY_BACKTRACE@
+#   endif
+#   define IK_DOT_OUTPUT @IK_DOT_OUTPUT@
+
+#endif /* IK_CONFIG_HPP */

+ 106 - 0
Source/ThirdParty/ik/ik/include/ik/effector.h

@@ -0,0 +1,106 @@
+#ifndef EFFECTOR_H
+#define EFFECTOR_H
+
+#include "ik/gen/config.h"
+#include "ik/pstdint.h"
+#include "ik/vec3.h"
+#include "ik/quat.h"
+
+C_HEADER_BEGIN
+
+struct ik_node_t;
+
+enum effector_flags_e
+{
+    /*!
+     * @brief Causes intermediary weight values to rotate the target around the
+     * chain's root instead of linearly interpolating the target. Can be more
+     * appealing if the solved tree diverges a lot from the original tree
+     * during weight transitions.
+     */
+    EFFECTOR_WEIGHT_NLERP            = 0x01,
+
+    EFFECTOR_INHERIT_PARENT_ROTATION = 0x02
+};
+
+/*!
+ * @brief Specifies how a chain of nodes should be solved. The effector can
+ * be attached to any node in a tree using ik_node_attach_effector(). The
+ * effector specifies the target position and rotation of that node, as well
+ * as how much influence the solver has on the tree (weight) and how many
+ * child nodes are affected (chain_length).
+ */
+struct ik_effector_t
+{
+    /*!
+     * @brief Can be set at any point, and should be updated whenever you have
+     * a new target position to solve for. Specifies the global (world)
+     * position where the node it is attached to should head for.
+     * @note Default value is (0, 0, 0).
+     */
+    vec3_t   target_position;
+
+    /*!
+     * @brief Can be set at any point, and should be updated whenever you have
+     * a new target rotation to solve for. Specifies the global (world)
+     * rotation where the node it is attached to should head for.
+     * @note Default value is the identity quaternion.
+     */
+    quat_t   target_rotation;
+
+    /*!
+     * @brief Specifies how much influence the solver has on the chain of
+     * nodes. A value of 0.0 will cause the solver to completely ignore the
+     * chain, while a value of 1.0 will cause the solver to try to place the
+     * target node directly at target_position/target_rotation.
+     *
+     * This is useful for blending the solver in and out. For instance, if you
+     * wanted to ground the legs of an animated character, you would want the
+     * solver to do nothing during the time when the foot is in the air
+     * (weight=0.0) and be fully active when the foot is on the ground
+     * (weight=1.0).
+     */
+    ik_real  weight;
+
+    ik_real rotation_weight;
+    ik_real rotation_decay;
+
+    /*!
+     * @brief Specifies how many parent nodes should be affected. A value of
+     * 0 means all of the parents, including the root node.
+     * @note Changing the chain length requires the solver tree to be rebuilt
+     * with ik_solver_rebuild_tree().
+     */
+    uint16_t chain_length;
+
+    /*!
+     * @brief Various behavioural settings. Check the enum effector_flags_e for
+     * more information.
+     */
+    uint8_t flags;
+};
+
+/*!
+ * @brief Creates a new effector object. It can be attached to any node in the
+ * tree using ik_node_attach_effector().
+ */
+IK_PUBLIC_API struct ik_effector_t*
+ik_effector_create(void);
+
+/*!
+ * @brief Constructs a previously allocated effector object.
+ */
+IK_PUBLIC_API void
+ik_effector_construct(struct ik_effector_t* effector);
+
+/*!
+ * @brief Destroys and frees an effector object. This should **NOT** be called
+ * on effectors that are attached to nodes. Use ik_node_destroy_effector()
+ * instead.
+ */
+IK_PUBLIC_API void
+ik_effector_destroy(struct ik_effector_t* effector);
+
+C_HEADER_END
+
+#endif /* EFFECTOR_H */

+ 120 - 0
Source/ThirdParty/ik/ik/include/ik/export.h.in

@@ -0,0 +1,120 @@
+/* ----------------------------------------------------------------
+ * Export and visibility amcros
+ * ----------------------------------------------------------------
+ * Substitution variables:
+ *  - PROJECT_NAME          : All-caps variable identifying the
+ *                            name of the project being built.
+ *  - BUILD_TYPE            : Set to either SHARED or STATIC.
+ * Global definitions (non substitution)
+ *  - PROJECT_NAME_BUILDING : Define this if the library is being
+ *                            built.
+ * ------------------------------------------------------------- */
+
+#ifndef IK_EXPORT_H
+#   define IK_EXPORT_H
+
+    /* set @BUILD_TYPE@ to SHARED or STATIC */
+#   define IK_STATIC
+
+    /* --------------------------------------------------------------
+     * define visibility macros
+     * --------------------------------------------------------------*/
+
+    /* define platform dependent and build dependent visibility macro helpers */
+#   if defined(IK_SHARED)
+#       if defined(IK_PLATFORM_WINDOWS)
+#           if defined(__GNUC__)
+                /* cygwin visbibility */
+#               define IK_HELPER_API_EXPORT __attribute__ ((dllexport))
+#               define IK_HELPER_API_IMPORT __attribute__ ((dllimport))
+#           else
+                /* msvc visibility */
+#               define IK_HELPER_API_EXPORT __declspec(dllexport)
+#               define IK_HELPER_API_IMPORT __declspec(dllimport)
+                /* disable warnings */
+#               pragma warning(disable: 4996) /* 'strcpy': This function or variable may be unsafe */
+#           endif
+#           define IK_HELPER_API_LOCAL
+#       else
+#           if __GNUC__ >= 4
+                /* gcc 4+ visibility */
+#               define IK_HELPER_API_EXPORT __attribute__ ((visibility ("default")))
+#               define IK_HELPER_API_IMPORT __attribute__ ((visibility ("default")))
+#               define IK_HELPER_API_LOCAL  __attribute__ ((visibility ("hidden")))
+#           else
+                /* gcc lower than 4 doesn't have any explicit visibility, everything is exported */
+#               define IK_HELPER_API_EXPORT
+#               define IK_HELPER_API_IMPORT
+#               define IK_HELPER_API_LOCAL
+#           endif
+#       endif
+#   elif defined(IK_STATIC)
+        /* static build */
+#       define IK_HELPER_API_EXPORT
+#       define IK_HELPER_API_IMPORT
+#       define IK_HELPER_API_LOCAL
+#   else
+#       error Please define IK_SHARED or IK_STATIC
+#   endif
+
+    /*
+     * define public API macro, depending on whether the library is being
+     * built or being linked against.
+     */
+#   if defined(IK_BUILDING) /* defined by CMake when library is being compiled */
+#       define IK_PUBLIC_API IK_HELPER_API_EXPORT
+#   else
+#       define IK_PUBLIC_API IK_HELPER_API_IMPORT
+#   endif
+
+    /*
+     * define local visibility macro. If we're testing, everything
+     * is visible
+     */
+#   if defined(TESTING)
+#       define IK_LOCAL_API IK_PUBLIC_API
+#   else
+#       define IK_LOCAL_API IK_HELPER_API_LOCAL
+#   endif
+
+    /*
+     * define class member visibility macros. If we're testing, everything
+     * is public
+     */
+#   if defined(TESTING)
+#       define PUBLIC public
+#       define PROTECTED public
+#       define PRIVATE public
+#   else
+#       define PUBLIC public
+#       define PROTECTED protected
+#       define PRIVATE private
+#   endif
+
+    /* --------------------------------------------------------------
+     * typeof support
+     * --------------------------------------------------------------*/
+
+#   if defined(__GNUC__)
+#       define TYPEOF(x) __typeof__(x)
+#   else
+#       undef TYPEOF
+#   endif
+
+    /* --------------------------------------------------------------
+     * C linkage
+     * --------------------------------------------------------------*/
+
+#   ifdef __cplusplus
+#       define C_HEADER_BEGIN extern "C" {
+#   else
+#       define C_HEADER_BEGIN
+#   endif
+
+#   ifdef __cplusplus
+#       define C_HEADER_END }
+#   else
+#       define C_HEADER_END
+#   endif
+
+#endif /* IK_EXPORT_H */

+ 8 - 0
Source/ThirdParty/ik/ik/include/ik/ik.h

@@ -0,0 +1,8 @@
+#ifndef IK_LIB_H
+#define IK_LIB_H
+
+#include "ik/solver.h"
+#include "ik/node.h"
+#include "ik/effector.h"
+
+#endif /* IK_LIB_H */

+ 33 - 0
Source/ThirdParty/ik/ik/include/ik/log.h

@@ -0,0 +1,33 @@
+#ifndef IK_LOG_H
+#define IK_LOG_H
+
+#include "ik/gen/config.h"
+
+C_HEADER_BEGIN
+
+typedef void (*ik_log_cb_func)(const char*);
+
+enum ik_log_e
+{
+    IK_LOG_NONE,
+    IK_LOG_STDOUT
+};
+
+IK_PUBLIC_API void
+ik_log_init(enum ik_log_e options);
+
+IK_PUBLIC_API void
+ik_log_deinit(void);
+
+IK_PUBLIC_API void
+ik_log_register_listener(ik_log_cb_func callback);
+
+IK_PUBLIC_API void
+ik_log_unregister_listener(ik_log_cb_func callback);
+
+IK_PUBLIC_API void
+ik_log_message(const char* fmt, ...);
+
+C_HEADER_END
+
+#endif /* IK_LOG_H */

+ 58 - 0
Source/ThirdParty/ik/ik/include/ik/memory.h

@@ -0,0 +1,58 @@
+#ifndef MEMORY_H
+#define MEMORY_H
+
+#include "ik/gen/config.h"
+#include "ik/pstdint.h"
+
+#if IK_MEMORY_DEBUGGING == ON
+#   define MALLOC malloc_wrapper
+#   define FREE   free_wrapper
+#else
+#   include <stdlib.h>
+#   define MALLOC malloc
+#   define FREE   free
+#endif
+
+C_HEADER_BEGIN
+
+/*!
+ * @brief Initialises the memory system.
+ *
+ * In release mode this does nothing. In debug mode it will initialise
+ * memory reports and backtraces, if enabled.
+ */
+IK_PUBLIC_API void
+ik_memory_init(void);
+
+/*!
+ * @brief De-initialises the memory system.
+ *
+ * In release mode this does nothing. In debug mode this will output the memory
+ * report and print backtraces, if enabled.
+ * @return Returns the number of memory leaks.
+ */
+IK_PUBLIC_API uintptr_t
+ik_memory_deinit(void);
+
+#if IK_MEMORY_DEBUGGING == ON
+/*!
+ * @brief Does the same thing as a normal call to malloc(), but does some
+ * additional work to monitor and track down memory leaks.
+ */
+IK_PUBLIC_API void*
+malloc_wrapper(intptr_t size);
+
+/*!
+ * @brief Does the same thing as a normal call to fee(), but does some
+ * additional work to monitor and track down memory leaks.
+ */
+IK_PUBLIC_API void
+free_wrapper(void* ptr);
+#endif /* IK_MEMORY_DEBUGGING */
+
+IK_PUBLIC_API void
+mutated_string_and_hex_dump(void* data, intptr_t size_in_bytes);
+
+C_HEADER_END
+
+#endif /* MEMORY_H */

+ 176 - 0
Source/ThirdParty/ik/ik/include/ik/node.h

@@ -0,0 +1,176 @@
+#ifndef IK_NODE_H
+#define IK_NODE_H
+
+#include "ik/gen/config.h"
+#include "ik/pstdint.h"
+#include "ik/bst_vector.h"
+#include "ik/vec3.h"
+#include "ik/quat.h"
+
+C_HEADER_BEGIN
+
+struct ik_effector_t;
+
+/*!
+ * @brief Represents one node in the tree to be solved.
+ */
+struct ik_node_t
+{
+    /*!
+     * @brief Allows the user of this library to store custom data per node
+     * @note Can be set and retrieved directly without issue.
+     *
+     * This is especially useful in c++ applications which need to store the
+     * "this" pointer to their own scene graph nodes. The user data can be
+     * accessed in callback functions to make object calls again.
+     *
+     * For instance:
+     * ```cpp
+     * // A node in your scene graph
+     * MyNode* node = GetMyNode();
+     *
+     * struct ik_solver_t* solver = ik_solver_create(SOLVER_FABRIK);
+     * struct ik_node_t* ikNode = ik_node_create(node->GetID());
+     * ikNode->user_data = node; // Store pointer to your own node object
+     *
+     * // ---- elsewhere ------
+     * static void ApplyResultsCallback(ik_node_t* ikNode)
+     * {
+     *     Node* node = (Node*)ikNode->user_data; // Extract your own node object again
+     *     node->SetPosition(ikNode->solved_position);
+     * }
+     * ```
+     */
+    void* user_data;
+
+    /*!
+     * @brief The initial global position (in world space).
+     * @note Must be set by the user to get correct results. This value can
+     * be set and retrieved at any time.
+     * @note The default value is (0, 0, 0).
+     */
+    vec3_t position;
+
+    /*!
+     * @brief The initial global rotation (in world space).
+     * @note Must be set by the user to get correct results if the solver has
+     * angle computations enabled (SOLVER_CALCULATE_FINAL_ANGLES).
+     * @note The default value is the identity quaternion.
+     */
+    quat_t rotation;
+
+    /*!
+     * @brief Global identifier for this node. The identifier must be unique
+     * within the tree, but separate trees may re-use the same IDs again. The
+     * ID can later be used to retrieve nodes from the tree again.
+     */
+    uint32_t guid;
+
+    /*!
+     * @brief After the solver is executed, the solved global (world) position
+     * is stored here and can be retrieved.
+     */
+    vec3_t solved_position;
+
+    /*!
+     * @brief After the solver is executed, the solved global (world) rotation
+     * is stored here and can be retrieved.
+     */
+    quat_t solved_rotation;
+
+    /*!
+     * @brief The end effector object.
+     * @note This pointer should not be changed directly. You can however set
+     * the target position/rotation of the effector by writing to
+     * node->effector->target_position or node->effector->target_rotation.
+     * @note May be NULL.
+     */
+    struct ik_effector_t* effector;
+
+    /* Private data */
+    ik_real segment_length;
+    struct ik_node_t* parent;
+    struct bstv_t children;
+};
+
+/*!
+ * @brief Creates a new node and returns it. Each node requires a tree-unique
+ * ID, which can be used later to search for nodes in the tree.
+ */
+IK_PUBLIC_API struct ik_node_t*
+ik_node_create(uint32_t guid);
+
+/*!
+ * @brief Constructs an already allocated node.
+ */
+IK_PUBLIC_API void
+ik_node_construct(struct ik_node_t* node, uint32_t guid);
+
+/*!
+ * @brief Destructs a node, destroying all children in the process, but does
+ * not deallocate the node object itself.
+ */
+IK_PUBLIC_API void
+ik_node_destruct(struct ik_node_t* node);
+
+/*!
+ * @brief Destructs and frees the node, destroying all children in the process.
+ * If the node was part of a tree, then it will be removed from its parents.
+ * @note You will need to rebuild the solver's tree before solving.
+ */
+IK_PUBLIC_API void
+ik_node_destroy(struct ik_node_t* node);
+
+/*!
+ * @brief Attaches a node as a child to another node. The parent node gains
+ * ownership of the child node and is responsible for deallocating it.
+ * @note You will need to rebuild the solver's tree before solving.
+ */
+IK_PUBLIC_API void
+ik_node_add_child(struct ik_node_t* node, struct ik_node_t* child);
+
+/*!
+ * @brief Unlinks a node from the tree, without destroying anything. All
+ * children of the unlinked node remain in tact and will no longer be
+ * affiliated with the original tree.
+ * @note You will need to rebuild the solver's tree before solving.
+ */
+IK_PUBLIC_API void
+ik_node_unlink(struct ik_node_t* node);
+
+/*!
+ * @brief Searches recursively for a node in a tree with the specified global
+ * identifier.
+ * @return Returns NULL if the node was not found, otherwise the node is
+ * returned.
+ */
+IK_PUBLIC_API struct ik_node_t*
+ik_node_find_child(struct ik_node_t* node, uint32_t guid);
+
+/*!
+ * @brief Attaches an effector object to the node. The node gains ownership
+ * of the effector and is responsible for its deallocation. If the node
+ * already owns an effector, then it is first destroyed.
+ * @note You will need to rebuild the solver's tree before solving.
+ */
+IK_PUBLIC_API void
+ik_node_attach_effector(struct ik_node_t* node, struct ik_effector_t* effector);
+
+/*!
+ * @brief Removes and destroys the node's effector, if it exists. The attribute
+ * node->effector is set to NULL.
+ * @note You will need to rebuild the solver's tree before solving.
+ */
+IK_PUBLIC_API void
+ik_node_destroy_effector(struct ik_node_t* node);
+
+/*!
+ * @brief Dumps all nodes recursively to DOT format. You can use graphviz (
+ * or other compatible tools) to generate a graphic of the tree.
+ */
+IK_PUBLIC_API void
+ik_node_dump_to_dot(struct ik_node_t* node, const char* file_name);
+
+C_HEADER_END
+
+#endif /* IK_NODE_H */

+ 297 - 0
Source/ThirdParty/ik/ik/include/ik/ordered_vector.h

@@ -0,0 +1,297 @@
+/*!
+ * @file ordered_vector.h
+ * @brief Dynamic contiguous sequence container with guaranteed element order.
+ * @page ordered_vector Ordered Vector
+ *
+ * Ordered vectors arrange all inserted elements next to each other in memory.
+ * Because of this, vector access is just as efficient as a normal array, but
+ * they are able to grow and shrink in size automatically.
+ */
+
+#ifndef ORDERED_VECTOR_H
+#define ORDERED_VECTOR_H
+
+#include "ik/gen/config.h"
+#include "ik/pstdint.h"
+
+C_HEADER_BEGIN
+
+#define DATA_POINTER_TYPE unsigned char
+struct ordered_vector_t
+{
+    uint32_t element_size;       /* how large one element is in bytes */
+    uint32_t capacity;           /* how many elements actually fit into the allocated space */
+    uint32_t count;              /* number of elements inserted */
+    DATA_POINTER_TYPE* data;     /* pointer to the contiguous section of memory */
+};
+
+/*!
+ * @brief Creates a new vector object. See @ref ordered_vector for details.
+ * @param[in] element_size Specifies the size in bytes of the type of data you want
+ * the vector to store. Typically one would pass sizeof(my_data_type).
+ * @return Returns the newly created vector object.
+ */
+IK_PUBLIC_API struct ordered_vector_t*
+ordered_vector_create(uint32_t element_size);
+
+/*!
+ * @brief Initialises an existing vector object.
+ * @note This does **not** free existing memory. If you've pushed elements
+ * into your vector and call this, you will have created a memory leak.
+ * @param[in] vector The vector to initialise.
+ * @param[in] element_size Specifies the size in bytes of the type of data you
+ * want the vector to store. Typically one would pass sizeof(my_data_type).
+ */
+IK_PUBLIC_API void
+ordered_vector_construct(struct ordered_vector_t* vector,
+                           uint32_t element_size);
+
+/*!
+ * @brief Destroys an existing vector object and frees all memory allocated by
+ * inserted elements.
+ * @param[in] vector The vector to destroy.
+ */
+IK_PUBLIC_API void
+ordered_vector_destroy(struct ordered_vector_t* vector);
+
+/*!
+ * @brief Erases all elements in a vector.
+ * @note This does not actually erase the underlying memory, it simply resets
+ * the element counter. If you wish to free the underlying memory, see
+ * ordered_vector_clear_free().
+ * @param[in] vector The vector to clear.
+ */
+IK_PUBLIC_API void
+ordered_vector_clear(struct ordered_vector_t* vector);
+
+/*!
+ * @brief Erases all elements in a vector and frees their memory.
+ * @param[in] vector The vector to clear.
+ */
+IK_PUBLIC_API void
+ordered_vector_clear_free(struct ordered_vector_t* vector);
+
+/*!
+ * @brief Sets the size of the vector to exactly the size specified. If the
+ * vector was smaller then memory will be reallocated. If the vector was larger
+ * then no reallocation will occur. The capacity will remain the same and the
+ * size will be decreased.
+ * @param[in] vector The vector to resize.
+ * @param[in] size The new size of the vector.
+ * @return Returns -1 on failure, 0 on success.
+ */
+IK_PUBLIC_API int
+ordered_vector_resize(struct ordered_vector_t* vector, uint32_t size);
+
+/*!
+ * @brief Gets the number of elements that have been inserted into the vector.
+ */
+#define ordered_vector_count(x) ((x)->count)
+
+/*!
+ * @brief Inserts (copies) a new element at the head of the vector.
+ * @note This can cause a re-allocation of the underlying memory. This
+ * implementation expands the allocated memory by a factor of 2 every time a
+ * re-allocation occurs to cut down on the frequency of re-allocations.
+ * @note If you do not wish to copy data into the vector, but merely make
+ * space, see ordered_vector_push_emplace().
+ * @param[in] vector The vector to push into.
+ * @param[in] data The data to copy into the vector. It is assumed that
+ * sizeof(data) is equal to what was specified when the vector was first
+ * created. If this is not the case then it could cause undefined behaviour.
+ * @return Returns 0 if the data was successfully pushed, -1 if
+ * otherwise.
+ */
+IK_PUBLIC_API int
+ordered_vector_push(struct ordered_vector_t* vector, void* data);
+
+/*!
+ * @brief Allocates space for a new element at the head of the vector, but does
+ * not initialise it.
+ * @warning The returned pointer could be invalidated if any other
+ * vector related function is called, as the underlying memory of the vector
+ * could be re-allocated. Use the pointer immediately after calling this
+ * function.
+ * @param[in] vector The vector to emplace an element into.
+ * @return A pointer to the allocated memory for the requested element. See
+ * warning and use with caution.
+ */
+IK_PUBLIC_API void*
+ordered_vector_push_emplace(struct ordered_vector_t* vector);
+
+/*!
+ * @brief Copies the contents of another vector and pushes it into the vector.
+ * @return Returns 0 if successful, -1 if otherwise.
+ */
+IK_PUBLIC_API int
+ordered_vector_push_vector(struct ordered_vector_t* vector, struct ordered_vector_t* source_vector);
+
+/*!
+ * @brief Removes an element from the back (end) of the vector.
+ * @warning The returned pointer could be invalidated if any other
+ * vector related function is called, as the underlying memory of the vector
+ * could be re-allocated. Use the pointer immediately after calling this
+ * function.
+ * @param[in] vector The vector to pop an element from.
+ * @return A pointer to the popped element. See warning and use with caution.
+ * If there are no elements to pop, NULL is returned.
+ */
+IK_PUBLIC_API void*
+ordered_vector_pop(struct ordered_vector_t* vector);
+
+/*!
+ * @brief Returns the very last element of the vector.
+ * @warning The returned pointer could be invalidated if any other vector
+ * related function is called, as the underlying memory of the vector could be
+ * re-allocated. Use the pointer immediately after calling this function.
+ *
+ * @param[in] vector The vector to return the last element from.
+ * @return A pointer to the last element. See warning and use with caution.
+ * If there are no elements in the vector, NULL is returned.
+ */
+IK_PUBLIC_API void*
+ordered_vector_back(const struct ordered_vector_t* vector);
+
+/*!
+ * @brief Allocates space for a new element at the specified index, but does
+ * not initialise it.
+ * @note This can cause a re-allocation of the underlying memory. This
+ * implementation expands the allocated memory by a factor of 2 every time a
+ * re-allocation occurs to cut down on the frequency of re-allocations.
+ * @warning The returned pointer could be invalidated if any other
+ * vector related function is called, as the underlying memory of the vector
+ * could be re-allocated. Use the pointer immediately after calling this
+ * function.
+ * @param[in] vector The vector to emplace an element into.
+ * @param[in] index Where to insert.
+ * @return A pointer to the emplaced element. See warning and use with caution.
+ */
+IK_PUBLIC_API void*
+ordered_vector_insert_emplace(struct ordered_vector_t* vector, uint32_t index);
+
+/*!
+ * @brief Inserts (copies) a new element at the specified index.
+ * @note This can cause a re-allocation of the underlying memory. This
+ * implementation expands the allocated memory by a factor of 2 every time a
+ * re-allocation occurs to cut down on the frequency of re-allocations.
+ * @note If you do not wish to copy data into the vector, but merely make
+ * space, see ordered_vector_insert_emplace().
+ * @param[in] vector The vector to insert into.
+ * @param[in] data The data to copy into the vector. It is assumed that
+ * sizeof(data) is equal to what was specified when the vector was first
+ * created. If this is not the case then it could cause undefined behaviour.
+ */
+IK_PUBLIC_API int
+ordered_vector_insert(struct ordered_vector_t* vector, uint32_t index, void* data);
+
+/*!
+ * @brief Erases the specified element from the vector.
+ * @note This causes all elements with indices greater than **index** to be
+ * re-allocated (shifted 1 element down) so the vector remains contiguous.
+ * @param[in] index The position of the element in the vector to erase. The index
+ * ranges from **0** to **ordered_vector_count()-1**.
+ */
+IK_PUBLIC_API void
+ordered_vector_erase_index(struct ordered_vector_t* vector, uint32_t index);
+
+/*!
+ * @brief Removes the element in the vector pointed to by **element**.
+ * @param[in] vector The vector from which to erase the data.
+ * @param[in] element A pointer to an element within the vector.
+ */
+IK_PUBLIC_API void
+ordered_vector_erase_element(struct ordered_vector_t* vector, void* element);
+
+/*!
+ * @brief Gets a pointer to the specified element in the vector.
+ * @warning The returned pointer could be invalidated if any other
+ * vector related function is called, as the underlying memory of the vector
+ * could be re-allocated. Use the pointer immediately after calling this
+ * function.
+ * @param[in] vector The vector to get the element from.
+ * @param[in] index The index of the element to get. The index ranges from
+ * **0** to **ordered_vector_count()-1**.
+ * @return [in] A pointer to the element. See warning and use with caution.
+ * If the specified element doesn't exist (index out of bounds), NULL is
+ * returned.
+ */
+IK_PUBLIC_API void*
+ordered_vector_get_element(struct ordered_vector_t*, uint32_t index);
+
+/*!
+ * @brief Convenient macro for iterating a vector's elements.
+ *
+ * Example:
+ * ```
+ * ordered_vector_t* some_vector = (a vector containing elements of type "struct bar")
+ * ORDERED_VECTOR_FOR_EACH(some_vector, struct bar, element)
+ * {
+ *     do_something_with(element);  ("element" is now of type "struct bar*")
+ * }
+ * ```
+ * @param[in] vector A pointer to the vector to iterate.
+ * @param[in] var_type Should be the type of data stored in the vector.
+ * @param[in] var The name of a temporary variable you'd like to use within the
+ * for-loop to reference the current element.
+ */
+#define ORDERED_VECTOR_FOR_EACH(vector, var_type, var) {                     \
+    var_type* var;                                                           \
+    DATA_POINTER_TYPE* internal_##var_end_of_vector = (vector)->data + (vector)->count * (vector)->element_size; \
+    for(var = (var_type*)(vector)->data;                                     \
+        (DATA_POINTER_TYPE*)var != internal_##var_end_of_vector;             \
+        var = (var_type*)(((DATA_POINTER_TYPE*)var) + (vector)->element_size)) {
+
+
+#define ORDERED_VECTOR_FOR_EACH_R(vector, var_type, var) {                   \
+    var_type* var;                                                           \
+    DATA_POINTER_TYPE* internal_##var_start_of_vector = (vector)->data - (vector)->element_size; \
+    for(var = (var_type*)((vector)->data + (vector)->count * (vector)->element_size - (vector)->element_size); \
+        (DATA_POINTER_TYPE*)var != internal_##var_start_of_vector;          \
+        var = (var_type*)(((DATA_POINTER_TYPE*)var) - (vector)->element_size)) {
+
+/*!
+ * @brief Convenient macro for iterating a range of a vector's elements.
+ * @param[in] vector A pointer to the vector to iterate.
+ * @param[in] var_type Should be the type of data stored in the vector. For
+ * example, if your vector is storing ```struct type_t*``` objects then
+ * var_type should equal ```struct type_t``` (without the pointer).
+ * @param[in] var The name of a temporary variable you'd like to use within the
+ * for loop to reference the current element.
+ * @param[in] begin_index The index (starting at 0) of the first element to
+ * start with.
+ * @param[in] end_index The index of the last element to iterate (exclusive).
+ */
+#define ORDERED_VECTOR_FOR_EACH_RANGE(vector, var_type, var, begin_index, end_index) { \
+    var_type* var;                                                                     \
+    DATA_POINTER_TYPE* internal_##var_end_of_vector = (vector)->data + end_index * (vector)->element_size; \
+    for(var = (var_type*)((vector)->data + begin_index * (vector)->element_size);      \
+        (DATA_POINTER_TYPE*)var != internal_##var_end_of_vector;                       \
+        var = (var_type*)(((DATA_POINTER_TYPE*)var) + (vector)->element_size)) {
+
+/*!
+ * @brief Closes a for each scope previously opened by ORDERED_VECTOR_FOR_EACH.
+ */
+#define ORDERED_VECTOR_END_EACH }}
+
+/*!
+ * @brief Convenient macro for erasing an element while iterating a vector.
+ * @warning Only call this while iterating.
+ * Example:
+ * ```
+ * ORDERED_VECTOR_FOR_EACH(some_vector, struct bar, element)
+ * {
+ *     ORDERED_VECTOR_ERASE_IN_FOR_LOOP(some_vector, struct bar, element);
+ * }
+ * ```
+ * @param[in] vector The vector to erase from.
+ * @param[in] var_type Should be the type of data stored in the vector.
+ * @param[in] element The element to erase.
+ */
+#define ORDERED_VECTOR_ERASE_IN_FOR_LOOP(vector, element_type, element)                \
+    ordered_vector_erase_element(vector, element);                                     \
+    element = (element_type*)(((DATA_POINTER_TYPE*)element) - (vector)->element_size); \
+    internal_##var_end_of_vector = (vector)->data + (vector)->count * (vector)->element_size;
+
+C_HEADER_END
+
+#endif /* ORDERED_VECTOR_H */

+ 813 - 0
Source/ThirdParty/ik/ik/include/ik/pstdint.h

@@ -0,0 +1,813 @@
+/*  A portable stdint.h
+ ****************************************************************************
+ *  BSD License:
+ ****************************************************************************
+ *
+ *  Copyright (c) 2005-2014 Paul Hsieh
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************
+ *
+ *  Version 0.1.14
+ *
+ *  The ANSI C standard committee, for the C99 standard, specified the
+ *  inclusion of a new standard include file called stdint.h.  This is
+ *  a very useful and long desired include file which contains several
+ *  very precise definitions for integer scalar types that is
+ *  critically important for making portable several classes of
+ *  applications including cryptography, hashing, variable length
+ *  integer libraries and so on.  But for most developers its likely
+ *  useful just for programming sanity.
+ *
+ *  The problem is that most compiler vendors have decided not to
+ *  implement the C99 standard, and the next C++ language standard
+ *  (which has a lot more mindshare these days) will be a long time in
+ *  coming and its unknown whether or not it will include stdint.h or
+ *  how much adoption it will have.  Either way, it will be a long time
+ *  before all compilers come with a stdint.h and it also does nothing
+ *  for the extremely large number of compilers available today which
+ *  do not include this file, or anything comparable to it.
+ *
+ *  So that's what this file is all about.  Its an attempt to build a
+ *  single universal include file that works on as many platforms as
+ *  possible to deliver what stdint.h is supposed to.  A few things
+ *  that should be noted about this file:
+ *
+ *    1) It is not guaranteed to be portable and/or present an identical
+ *       interface on all platforms.  The extreme variability of the
+ *       ANSI C standard makes this an impossibility right from the
+ *       very get go. Its really only meant to be useful for the vast
+ *       majority of platforms that possess the capability of
+ *       implementing usefully and precisely defined, standard sized
+ *       integer scalars.  Systems which are not intrinsically 2s
+ *       complement may produce invalid constants.
+ *
+ *    2) There is an unavoidable use of non-reserved symbols.
+ *
+ *    3) Other standard include files are invoked.
+ *
+ *    4) This file may come in conflict with future platforms that do
+ *       include stdint.h.  The hope is that one or the other can be
+ *       used with no real difference.
+ *
+ *    5) In the current verison, if your platform can't represent
+ *       int32_t, int16_t and int8_t, it just dumps out with a compiler
+ *       error.
+ *
+ *    6) 64 bit integers may or may not be defined.  Test for their
+ *       presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX.
+ *       Note that this is different from the C99 specification which
+ *       requires the existence of 64 bit support in the compiler.  If
+ *       this is not defined for your platform, yet it is capable of
+ *       dealing with 64 bits then it is because this file has not yet
+ *       been extended to cover all of your system's capabilities.
+ *
+ *    7) (u)intptr_t may or may not be defined.  Test for its presence
+ *       with the test: #ifdef PTRDIFF_MAX.  If this is not defined
+ *       for your platform, then it is because this file has not yet
+ *       been extended to cover all of your system's capabilities, not
+ *       because its optional.
+ *
+ *    8) The following might not been defined even if your platform is
+ *       capable of defining it:
+ *
+ *       WCHAR_MIN
+ *       WCHAR_MAX
+ *       (u)int64_t
+ *       PTRDIFF_MIN
+ *       PTRDIFF_MAX
+ *       (u)intptr_t
+ *
+ *    9) The following have not been defined:
+ *
+ *       WINT_MIN
+ *       WINT_MAX
+ *
+ *   10) The criteria for defining (u)int_least(*)_t isn't clear,
+ *       except for systems which don't have a type that precisely
+ *       defined 8, 16, or 32 bit types (which this include file does
+ *       not support anyways). Default definitions have been given.
+ *
+ *   11) The criteria for defining (u)int_fast(*)_t isn't something I
+ *       would trust to any particular compiler vendor or the ANSI C
+ *       committee.  It is well known that "compatible systems" are
+ *       commonly created that have very different performance
+ *       characteristics from the systems they are compatible with,
+ *       especially those whose vendors make both the compiler and the
+ *       system.  Default definitions have been given, but its strongly
+ *       recommended that users never use these definitions for any
+ *       reason (they do *NOT* deliver any serious guarantee of
+ *       improved performance -- not in this file, nor any vendor's
+ *       stdint.h).
+ *
+ *   12) The following macros:
+ *
+ *       PRINTF_INTMAX_MODIFIER
+ *       PRINTF_INT64_MODIFIER
+ *       PRINTF_INT32_MODIFIER
+ *       PRINTF_INT16_MODIFIER
+ *       PRINTF_LEAST64_MODIFIER
+ *       PRINTF_LEAST32_MODIFIER
+ *       PRINTF_LEAST16_MODIFIER
+ *       PRINTF_INTPTR_MODIFIER
+ *
+ *       are strings which have been defined as the modifiers required
+ *       for the "d", "u" and "x" printf formats to correctly output
+ *       (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t,
+ *       (u)least32_t, (u)least16_t and (u)intptr_t types respectively.
+ *       PRINTF_INTPTR_MODIFIER is not defined for some systems which
+ *       provide their own stdint.h.  PRINTF_INT64_MODIFIER is not
+ *       defined if INT64_MAX is not defined.  These are an extension
+ *       beyond what C99 specifies must be in stdint.h.
+ *
+ *       In addition, the following macros are defined:
+ *
+ *       PRINTF_INTMAX_HEX_WIDTH
+ *       PRINTF_INT64_HEX_WIDTH
+ *       PRINTF_INT32_HEX_WIDTH
+ *       PRINTF_INT16_HEX_WIDTH
+ *       PRINTF_INT8_HEX_WIDTH
+ *       PRINTF_INTMAX_DEC_WIDTH
+ *       PRINTF_INT64_DEC_WIDTH
+ *       PRINTF_INT32_DEC_WIDTH
+ *       PRINTF_INT16_DEC_WIDTH
+ *       PRINTF_INT8_DEC_WIDTH
+ *
+ *       Which specifies the maximum number of characters required to
+ *       print the number of that type in either hexadecimal or decimal.
+ *       These are an extension beyond what C99 specifies must be in
+ *       stdint.h.
+ *
+ *  Compilers tested (all with 0 warnings at their highest respective
+ *  settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32
+ *  bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio
+ *  .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3
+ *
+ *  This file should be considered a work in progress.  Suggestions for
+ *  improvements, especially those which increase coverage are strongly
+ *  encouraged.
+ *
+ *  Acknowledgements
+ *
+ *  The following people have made significant contributions to the
+ *  development and testing of this file:
+ *
+ *  Chris Howie
+ *  John Steele Scott
+ *  Dave Thorup
+ *  John Dill
+ *  Florian Wobbe
+ *  Christopher Sean Morrison
+ *
+ */
+
+#include <stddef.h>
+#include <limits.h>
+#include <signal.h>
+
+/*
+ *  For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and
+ *  do nothing else.  On the Mac OS X version of gcc this is _STDINT_H_.
+ */
+
+#if ((defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (__GNUC__ > 3 || defined(_STDINT_H) || defined(_STDINT_H_) || defined (__UINT_FAST64_TYPE__)) )) && !defined (_PSTDINT_H_INCLUDED)
+#include <stdint.h>
+#define _PSTDINT_H_INCLUDED
+# if defined(__GNUC__) && (defined(__x86_64__) || defined(__ppc64__))
+#  ifndef PRINTF_INT64_MODIFIER
+#   define PRINTF_INT64_MODIFIER "l"
+#  endif
+#  ifndef PRINTF_INT32_MODIFIER
+#   define PRINTF_INT32_MODIFIER ""
+#  endif
+# else
+#  ifndef PRINTF_INT64_MODIFIER
+#   define PRINTF_INT64_MODIFIER "ll"
+#  endif
+#  ifndef PRINTF_INT32_MODIFIER
+#   define PRINTF_INT32_MODIFIER "l"
+#  endif
+# endif
+# ifndef PRINTF_INT16_MODIFIER
+#  define PRINTF_INT16_MODIFIER "h"
+# endif
+# ifndef PRINTF_INTMAX_MODIFIER
+#  define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
+# endif
+# ifndef PRINTF_INT64_HEX_WIDTH
+#  define PRINTF_INT64_HEX_WIDTH "16"
+# endif
+# ifndef PRINTF_INT32_HEX_WIDTH
+#  define PRINTF_INT32_HEX_WIDTH "8"
+# endif
+# ifndef PRINTF_INT16_HEX_WIDTH
+#  define PRINTF_INT16_HEX_WIDTH "4"
+# endif
+# ifndef PRINTF_INT8_HEX_WIDTH
+#  define PRINTF_INT8_HEX_WIDTH "2"
+# endif
+# ifndef PRINTF_INT64_DEC_WIDTH
+#  define PRINTF_INT64_DEC_WIDTH "20"
+# endif
+# ifndef PRINTF_INT32_DEC_WIDTH
+#  define PRINTF_INT32_DEC_WIDTH "10"
+# endif
+# ifndef PRINTF_INT16_DEC_WIDTH
+#  define PRINTF_INT16_DEC_WIDTH "5"
+# endif
+# ifndef PRINTF_INT8_DEC_WIDTH
+#  define PRINTF_INT8_DEC_WIDTH "3"
+# endif
+# ifndef PRINTF_INTMAX_HEX_WIDTH
+#  define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
+# endif
+# ifndef PRINTF_INTMAX_DEC_WIDTH
+#  define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
+# endif
+
+/*
+ *  Something really weird is going on with Open Watcom.  Just pull some of
+ *  these duplicated definitions from Open Watcom's stdint.h file for now.
+ */
+
+# if defined (__WATCOMC__) && __WATCOMC__ >= 1250
+#  if !defined (INT64_C)
+#   define INT64_C(x)   (x + (INT64_MAX - INT64_MAX))
+#  endif
+#  if !defined (UINT64_C)
+#   define UINT64_C(x)  (x + (UINT64_MAX - UINT64_MAX))
+#  endif
+#  if !defined (INT32_C)
+#   define INT32_C(x)   (x + (INT32_MAX - INT32_MAX))
+#  endif
+#  if !defined (UINT32_C)
+#   define UINT32_C(x)  (x + (UINT32_MAX - UINT32_MAX))
+#  endif
+#  if !defined (INT16_C)
+#   define INT16_C(x)   (x)
+#  endif
+#  if !defined (UINT16_C)
+#   define UINT16_C(x)  (x)
+#  endif
+#  if !defined (INT8_C)
+#   define INT8_C(x)   (x)
+#  endif
+#  if !defined (UINT8_C)
+#   define UINT8_C(x)  (x)
+#  endif
+#  if !defined (UINT64_MAX)
+#   define UINT64_MAX  18446744073709551615ULL
+#  endif
+#  if !defined (INT64_MAX)
+#   define INT64_MAX  9223372036854775807LL
+#  endif
+#  if !defined (UINT32_MAX)
+#   define UINT32_MAX  4294967295UL
+#  endif
+#  if !defined (INT32_MAX)
+#   define INT32_MAX  2147483647L
+#  endif
+#  if !defined (INTMAX_MAX)
+#   define INTMAX_MAX INT64_MAX
+#  endif
+#  if !defined (INTMAX_MIN)
+#   define INTMAX_MIN INT64_MIN
+#  endif
+# endif
+#endif
+
+#ifndef _PSTDINT_H_INCLUDED
+#define _PSTDINT_H_INCLUDED
+
+#ifndef SIZE_MAX
+# define SIZE_MAX (~(size_t)0)
+#endif
+
+/*
+ *  Deduce the type assignments from limits.h under the assumption that
+ *  integer sizes in bits are powers of 2, and follow the ANSI
+ *  definitions.
+ */
+
+#ifndef UINT8_MAX
+# define UINT8_MAX 0xff
+#endif
+#if !defined(uint8_t) && !defined(_UINT8_T)
+# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S)
+	typedef unsigned char uint8_t;
+#   define UINT8_C(v) ((uint8_t) v)
+# else
+#   error "Platform not supported"
+# endif
+#endif
+
+#ifndef INT8_MAX
+# define INT8_MAX 0x7f
+#endif
+#ifndef INT8_MIN
+# define INT8_MIN INT8_C(0x80)
+#endif
+#if !defined(int8_t) && !defined(_INT8_T)
+# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S)
+	typedef signed char int8_t;
+#   define INT8_C(v) ((int8_t) v)
+# else
+#   error "Platform not supported"
+# endif
+#endif
+
+#ifndef UINT16_MAX
+# define UINT16_MAX 0xffff
+#endif
+#if !defined(uint16_t) && !defined(_UINT16_T)
+#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S)
+  typedef unsigned int uint16_t;
+# ifndef PRINTF_INT16_MODIFIER
+#  define PRINTF_INT16_MODIFIER ""
+# endif
+# define UINT16_C(v) ((uint16_t) (v))
+#elif (USHRT_MAX == UINT16_MAX)
+  typedef unsigned short uint16_t;
+# define UINT16_C(v) ((uint16_t) (v))
+# ifndef PRINTF_INT16_MODIFIER
+#  define PRINTF_INT16_MODIFIER "h"
+# endif
+#else
+#error "Platform not supported"
+#endif
+#endif
+
+#ifndef INT16_MAX
+# define INT16_MAX 0x7fff
+#endif
+#ifndef INT16_MIN
+# define INT16_MIN INT16_C(0x8000)
+#endif
+#if !defined(int16_t) && !defined(_INT16_T)
+#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S)
+  typedef signed int int16_t;
+# define INT16_C(v) ((int16_t) (v))
+# ifndef PRINTF_INT16_MODIFIER
+#  define PRINTF_INT16_MODIFIER ""
+# endif
+#elif (SHRT_MAX == INT16_MAX)
+  typedef signed short int16_t;
+# define INT16_C(v) ((int16_t) (v))
+# ifndef PRINTF_INT16_MODIFIER
+#  define PRINTF_INT16_MODIFIER "h"
+# endif
+#else
+#error "Platform not supported"
+#endif
+#endif
+
+#ifndef UINT32_MAX
+# define UINT32_MAX (0xffffffffUL)
+#endif
+#if !defined(uint32_t) && !defined(_UINT32_T)
+#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S)
+  typedef unsigned long uint32_t;
+# define UINT32_C(v) v ## UL
+# ifndef PRINTF_INT32_MODIFIER
+#  define PRINTF_INT32_MODIFIER "l"
+# endif
+#elif (UINT_MAX == UINT32_MAX)
+  typedef unsigned int uint32_t;
+# ifndef PRINTF_INT32_MODIFIER
+#  define PRINTF_INT32_MODIFIER ""
+# endif
+# define UINT32_C(v) v ## U
+#elif (USHRT_MAX == UINT32_MAX)
+  typedef unsigned short uint32_t;
+# define UINT32_C(v) ((unsigned short) (v))
+# ifndef PRINTF_INT32_MODIFIER
+#  define PRINTF_INT32_MODIFIER ""
+# endif
+#else
+#error "Platform not supported"
+#endif
+#endif
+
+#ifndef INT32_MAX
+# define INT32_MAX (0x7fffffffL)
+#endif
+#ifndef INT32_MIN
+# define INT32_MIN INT32_C(0x80000000)
+#endif
+#if !defined(int32_t) && !defined(_INT32_T)
+#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S)
+  typedef signed long int32_t;
+# define INT32_C(v) v ## L
+# ifndef PRINTF_INT32_MODIFIER
+#  define PRINTF_INT32_MODIFIER "l"
+# endif
+#elif (INT_MAX == INT32_MAX)
+  typedef signed int int32_t;
+# define INT32_C(v) v
+# ifndef PRINTF_INT32_MODIFIER
+#  define PRINTF_INT32_MODIFIER ""
+# endif
+#elif (SHRT_MAX == INT32_MAX)
+  typedef signed short int32_t;
+# define INT32_C(v) ((short) (v))
+# ifndef PRINTF_INT32_MODIFIER
+#  define PRINTF_INT32_MODIFIER ""
+# endif
+#else
+#error "Platform not supported"
+#endif
+#endif
+
+/*
+ *  The macro stdint_int64_defined is temporarily used to record
+ *  whether or not 64 integer support is available.  It must be
+ *  defined for any 64 integer extensions for new platforms that are
+ *  added.
+ */
+
+#undef stdint_int64_defined
+#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S)
+# if (__STDC__ && __STDC_VERSION__ >= 199901L) || defined (S_SPLINT_S)
+#  define stdint_int64_defined
+   typedef long long int64_t;
+   typedef unsigned long long uint64_t;
+#  define UINT64_C(v) v ## ULL
+#  define  INT64_C(v) v ## LL
+#  ifndef PRINTF_INT64_MODIFIER
+#   define PRINTF_INT64_MODIFIER "ll"
+#  endif
+# endif
+#endif
+
+#if !defined (stdint_int64_defined)
+# if defined(__GNUC__)
+#  define stdint_int64_defined
+   __extension__ typedef long long int64_t;
+   __extension__ typedef unsigned long long uint64_t;
+#  define UINT64_C(v) v ## ULL
+#  define  INT64_C(v) v ## LL
+#  ifndef PRINTF_INT64_MODIFIER
+#   define PRINTF_INT64_MODIFIER "ll"
+#  endif
+# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S)
+#  define stdint_int64_defined
+   typedef long long int64_t;
+   typedef unsigned long long uint64_t;
+#  define UINT64_C(v) v ## ULL
+#  define  INT64_C(v) v ## LL
+#  ifndef PRINTF_INT64_MODIFIER
+#   define PRINTF_INT64_MODIFIER "ll"
+#  endif
+# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC)
+#  define stdint_int64_defined
+   typedef __int64 int64_t;
+   typedef unsigned __int64 uint64_t;
+#  define UINT64_C(v) v ## UI64
+#  define  INT64_C(v) v ## I64
+#  ifndef PRINTF_INT64_MODIFIER
+#   define PRINTF_INT64_MODIFIER "I64"
+#  endif
+# endif
+#endif
+
+#if !defined (LONG_LONG_MAX) && defined (INT64_C)
+# define LONG_LONG_MAX INT64_C (9223372036854775807)
+#endif
+#ifndef ULONG_LONG_MAX
+# define ULONG_LONG_MAX UINT64_C (18446744073709551615)
+#endif
+
+#if !defined (INT64_MAX) && defined (INT64_C)
+# define INT64_MAX INT64_C (9223372036854775807)
+#endif
+#if !defined (INT64_MIN) && defined (INT64_C)
+# define INT64_MIN INT64_C (-9223372036854775808)
+#endif
+#if !defined (UINT64_MAX) && defined (INT64_C)
+# define UINT64_MAX UINT64_C (18446744073709551615)
+#endif
+
+/*
+ *  Width of hexadecimal for number field.
+ */
+
+#ifndef PRINTF_INT64_HEX_WIDTH
+# define PRINTF_INT64_HEX_WIDTH "16"
+#endif
+#ifndef PRINTF_INT32_HEX_WIDTH
+# define PRINTF_INT32_HEX_WIDTH "8"
+#endif
+#ifndef PRINTF_INT16_HEX_WIDTH
+# define PRINTF_INT16_HEX_WIDTH "4"
+#endif
+#ifndef PRINTF_INT8_HEX_WIDTH
+# define PRINTF_INT8_HEX_WIDTH "2"
+#endif
+
+#ifndef PRINTF_INT64_DEC_WIDTH
+# define PRINTF_INT64_DEC_WIDTH "20"
+#endif
+#ifndef PRINTF_INT32_DEC_WIDTH
+# define PRINTF_INT32_DEC_WIDTH "10"
+#endif
+#ifndef PRINTF_INT16_DEC_WIDTH
+# define PRINTF_INT16_DEC_WIDTH "5"
+#endif
+#ifndef PRINTF_INT8_DEC_WIDTH
+# define PRINTF_INT8_DEC_WIDTH "3"
+#endif
+
+/*
+ *  Ok, lets not worry about 128 bit integers for now.  Moore's law says
+ *  we don't need to worry about that until about 2040 at which point
+ *  we'll have bigger things to worry about.
+ */
+
+#ifdef stdint_int64_defined
+  typedef int64_t intmax_t;
+  typedef uint64_t uintmax_t;
+# define  INTMAX_MAX   INT64_MAX
+# define  INTMAX_MIN   INT64_MIN
+# define UINTMAX_MAX  UINT64_MAX
+# define UINTMAX_C(v) UINT64_C(v)
+# define  INTMAX_C(v)  INT64_C(v)
+# ifndef PRINTF_INTMAX_MODIFIER
+#   define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
+# endif
+# ifndef PRINTF_INTMAX_HEX_WIDTH
+#  define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
+# endif
+# ifndef PRINTF_INTMAX_DEC_WIDTH
+#  define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
+# endif
+#else
+  typedef int32_t intmax_t;
+  typedef uint32_t uintmax_t;
+# define  INTMAX_MAX   INT32_MAX
+# define UINTMAX_MAX  UINT32_MAX
+# define UINTMAX_C(v) UINT32_C(v)
+# define  INTMAX_C(v)  INT32_C(v)
+# ifndef PRINTF_INTMAX_MODIFIER
+#   define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER
+# endif
+# ifndef PRINTF_INTMAX_HEX_WIDTH
+#  define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH
+# endif
+# ifndef PRINTF_INTMAX_DEC_WIDTH
+#  define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH
+# endif
+#endif
+
+/*
+ *  Because this file currently only supports platforms which have
+ *  precise powers of 2 as bit sizes for the default integers, the
+ *  least definitions are all trivial.  Its possible that a future
+ *  version of this file could have different definitions.
+ */
+
+#ifndef stdint_least_defined
+  typedef   int8_t   int_least8_t;
+  typedef  uint8_t  uint_least8_t;
+  typedef  int16_t  int_least16_t;
+  typedef uint16_t uint_least16_t;
+  typedef  int32_t  int_least32_t;
+  typedef uint32_t uint_least32_t;
+# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER
+# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER
+# define  UINT_LEAST8_MAX  UINT8_MAX
+# define   INT_LEAST8_MAX   INT8_MAX
+# define UINT_LEAST16_MAX UINT16_MAX
+# define  INT_LEAST16_MAX  INT16_MAX
+# define UINT_LEAST32_MAX UINT32_MAX
+# define  INT_LEAST32_MAX  INT32_MAX
+# define   INT_LEAST8_MIN   INT8_MIN
+# define  INT_LEAST16_MIN  INT16_MIN
+# define  INT_LEAST32_MIN  INT32_MIN
+# ifdef stdint_int64_defined
+	typedef  int64_t  int_least64_t;
+	typedef uint64_t uint_least64_t;
+#   define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER
+#   define UINT_LEAST64_MAX UINT64_MAX
+#   define  INT_LEAST64_MAX  INT64_MAX
+#   define  INT_LEAST64_MIN  INT64_MIN
+# endif
+#endif
+#undef stdint_least_defined
+
+/*
+ *  The ANSI C committee pretending to know or specify anything about
+ *  performance is the epitome of misguided arrogance.  The mandate of
+ *  this file is to *ONLY* ever support that absolute minimum
+ *  definition of the fast integer types, for compatibility purposes.
+ *  No extensions, and no attempt to suggest what may or may not be a
+ *  faster integer type will ever be made in this file.  Developers are
+ *  warned to stay away from these types when using this or any other
+ *  stdint.h.
+ */
+
+typedef   int_least8_t   int_fast8_t;
+typedef  uint_least8_t  uint_fast8_t;
+typedef  int_least16_t  int_fast16_t;
+typedef uint_least16_t uint_fast16_t;
+typedef  int_least32_t  int_fast32_t;
+typedef uint_least32_t uint_fast32_t;
+#define  UINT_FAST8_MAX  UINT_LEAST8_MAX
+#define   INT_FAST8_MAX   INT_LEAST8_MAX
+#define UINT_FAST16_MAX UINT_LEAST16_MAX
+#define  INT_FAST16_MAX  INT_LEAST16_MAX
+#define UINT_FAST32_MAX UINT_LEAST32_MAX
+#define  INT_FAST32_MAX  INT_LEAST32_MAX
+#define   INT_FAST8_MIN   INT_LEAST8_MIN
+#define  INT_FAST16_MIN  INT_LEAST16_MIN
+#define  INT_FAST32_MIN  INT_LEAST32_MIN
+#ifdef stdint_int64_defined
+  typedef  int_least64_t  int_fast64_t;
+  typedef uint_least64_t uint_fast64_t;
+# define UINT_FAST64_MAX UINT_LEAST64_MAX
+# define  INT_FAST64_MAX  INT_LEAST64_MAX
+# define  INT_FAST64_MIN  INT_LEAST64_MIN
+#endif
+
+#undef stdint_int64_defined
+
+/*
+ *  Whatever piecemeal, per compiler thing we can do about the wchar_t
+ *  type limits.
+ */
+
+#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__)
+# include <wchar.h>
+# ifndef WCHAR_MIN
+#  define WCHAR_MIN 0
+# endif
+# ifndef WCHAR_MAX
+#  define WCHAR_MAX ((wchar_t)-1)
+# endif
+#endif
+
+/*
+ *  Whatever piecemeal, per compiler/platform thing we can do about the
+ *  (u)intptr_t types and limits.
+ */
+
+#if (defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED)) || defined (_UINTPTR_T)
+# define STDINT_H_UINTPTR_T_DEFINED
+#endif
+
+#ifndef STDINT_H_UINTPTR_T_DEFINED
+# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64) || defined (__ppc64__)
+#  define stdint_intptr_bits 64
+# elif defined (__WATCOMC__) || defined (__TURBOC__)
+#  if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
+#    define stdint_intptr_bits 16
+#  else
+#    define stdint_intptr_bits 32
+#  endif
+# elif defined (__i386__) || defined (_WIN32) || defined (WIN32) || defined (__ppc64__)
+#  define stdint_intptr_bits 32
+# elif defined (__INTEL_COMPILER)
+/* TODO -- what did Intel do about x86-64? */
+# else
+/* #error "This platform might not be supported yet" */
+# endif
+
+# ifdef stdint_intptr_bits
+#  define stdint_intptr_glue3_i(a,b,c)  a##b##c
+#  define stdint_intptr_glue3(a,b,c)    stdint_intptr_glue3_i(a,b,c)
+#  ifndef PRINTF_INTPTR_MODIFIER
+#    define PRINTF_INTPTR_MODIFIER      stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER)
+#  endif
+#  ifndef PTRDIFF_MAX
+#    define PTRDIFF_MAX                 stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
+#  endif
+#  ifndef PTRDIFF_MIN
+#    define PTRDIFF_MIN                 stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
+#  endif
+#  ifndef UINTPTR_MAX
+#    define UINTPTR_MAX                 stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX)
+#  endif
+#  ifndef INTPTR_MAX
+#    define INTPTR_MAX                  stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
+#  endif
+#  ifndef INTPTR_MIN
+#    define INTPTR_MIN                  stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
+#  endif
+#  ifndef INTPTR_C
+#    define INTPTR_C(x)                 stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x)
+#  endif
+#  ifndef UINTPTR_C
+#    define UINTPTR_C(x)                stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x)
+#  endif
+  typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t;
+  typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t)  intptr_t;
+# else
+/* TODO -- This following is likely wrong for some platforms, and does
+   nothing for the definition of uintptr_t. */
+  typedef ptrdiff_t intptr_t;
+# endif
+# define STDINT_H_UINTPTR_T_DEFINED
+#endif
+
+/*
+ *  Assumes sig_atomic_t is signed and we have a 2s complement machine.
+ */
+
+#ifndef SIG_ATOMIC_MAX
+# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1)
+#endif
+
+#endif
+
+#if defined (__TEST_PSTDINT_FOR_CORRECTNESS)
+
+/*
+ *  Please compile with the maximum warning settings to make sure macros are not
+ *  defined more than once.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define glue3_aux(x,y,z) x ## y ## z
+#define glue3(x,y,z) glue3_aux(x,y,z)
+
+#define DECLU(bits) glue3(uint,bits,_t) glue3(u,bits,) = glue3(UINT,bits,_C) (0);
+#define DECLI(bits) glue3(int,bits,_t) glue3(i,bits,) = glue3(INT,bits,_C) (0);
+
+#define DECL(us,bits) glue3(DECL,us,) (bits)
+
+#define TESTUMAX(bits) glue3(u,bits,) = ~glue3(u,bits,); if (glue3(UINT,bits,_MAX) != glue3(u,bits,)) printf ("Something wrong with UINT%d_MAX\n", bits)
+
+int main () {
+	DECL(I,8)
+	DECL(U,8)
+	DECL(I,16)
+	DECL(U,16)
+	DECL(I,32)
+	DECL(U,32)
+#ifdef INT64_MAX
+	DECL(I,64)
+	DECL(U,64)
+#endif
+	intmax_t imax = INTMAX_C(0);
+	uintmax_t umax = UINTMAX_C(0);
+	char str0[256], str1[256];
+
+	sprintf (str0, "%d %x\n", 0, ~0);
+
+	sprintf (str1, "%d %x\n",  i8, ~0);
+	if (0 != strcmp (str0, str1)) printf ("Something wrong with i8 : %s\n", str1);
+	sprintf (str1, "%u %x\n",  u8, ~0);
+	if (0 != strcmp (str0, str1)) printf ("Something wrong with u8 : %s\n", str1);
+	sprintf (str1, "%d %x\n",  i16, ~0);
+	if (0 != strcmp (str0, str1)) printf ("Something wrong with i16 : %s\n", str1);
+	sprintf (str1, "%u %x\n",  u16, ~0);
+	if (0 != strcmp (str0, str1)) printf ("Something wrong with u16 : %s\n", str1);
+	sprintf (str1, "%" PRINTF_INT32_MODIFIER "d %x\n",  i32, ~0);
+	if (0 != strcmp (str0, str1)) printf ("Something wrong with i32 : %s\n", str1);
+	sprintf (str1, "%" PRINTF_INT32_MODIFIER "u %x\n",  u32, ~0);
+	if (0 != strcmp (str0, str1)) printf ("Something wrong with u32 : %s\n", str1);
+#ifdef INT64_MAX
+	sprintf (str1, "%" PRINTF_INT64_MODIFIER "d %x\n",  i64, ~0);
+	if (0 != strcmp (str0, str1)) printf ("Something wrong with i64 : %s\n", str1);
+#endif
+	sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "d %x\n",  imax, ~0);
+	if (0 != strcmp (str0, str1)) printf ("Something wrong with imax : %s\n", str1);
+	sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "u %x\n",  umax, ~0);
+	if (0 != strcmp (str0, str1)) printf ("Something wrong with umax : %s\n", str1);
+
+	TESTUMAX(8);
+	TESTUMAX(16);
+	TESTUMAX(32);
+#ifdef INT64_MAX
+	TESTUMAX(64);
+#endif
+
+	return EXIT_SUCCESS;
+}
+
+#endif

+ 101 - 0
Source/ThirdParty/ik/ik/include/ik/quat.h

@@ -0,0 +1,101 @@
+#ifndef QUATERNION_H
+#define QUATERNION_H
+
+#include "ik/gen/config.h"
+#include "ik/vec3.h"
+
+C_HEADER_BEGIN
+
+typedef union quat_t
+{
+    struct {
+        ik_real x;
+        ik_real y;
+        ik_real z;
+        ik_real w;
+    } q;
+    struct {
+        vec3_t v;
+        ik_real w;
+    } vw;
+    ik_real f[4];
+} quat_t;
+
+/*!
+ * @brief Sets the quaternion to its identity rotation.
+ */
+IK_PUBLIC_API void
+quat_set_identity(ik_real* q);
+
+/*!
+ * @brief Adds the elements from one quaternion to another. Required for
+ * averaging multiple quaternions.
+ */
+IK_PUBLIC_API void
+quat_add_quat(ik_real* q1, const ik_real* q2);
+
+/*!
+ * @brief Calculates the magnitude of a quaternion.
+ */
+IK_PUBLIC_API ik_real
+quat_mag(const ik_real* q);
+
+/*!
+ * @brief Inverts the sign of the vector part of the quaternion (conjugation).
+ */
+IK_PUBLIC_API void
+quat_conj(ik_real* q);
+
+/*!
+ * @brief Inverts the sign of all elements (NOT conjugation).
+ */
+IK_PUBLIC_API void
+quat_invert_sign(ik_real* q);
+
+/*!
+ * @brief Normalises the quaternion.
+ */
+IK_PUBLIC_API void
+quat_normalise(ik_real* q);
+
+/*!
+ * @brief Multiplies two quaternions together.
+ */
+IK_PUBLIC_API void
+quat_mul_quat(ik_real* q1, const ik_real* q2);
+
+/*!
+ * @brief Multiplies each component by a constant.
+ */
+IK_PUBLIC_API void
+quat_mul_scalar(ik_real* q, ik_real scalar);
+
+/*!
+ * @brief Divides each component by a constant. If the constant is 0 then the
+ * result will be a unit quaternion.
+ */
+IK_PUBLIC_API void
+quat_div_scalar(ik_real* q, ik_real scalar);
+
+/*!
+ * @brief Calculates the scalar product of two quaternions.
+ */
+IK_PUBLIC_API ik_real
+quat_dot(ik_real* q1, const ik_real* q2);
+
+/*!
+ * @brief Rotations a vector by the specified quaternion.
+ */
+IK_PUBLIC_API void
+quat_rotate_vec(ik_real* v, const ik_real* q);
+
+/*!
+ * @brief Returns 0 if the two quaternions are "close", i.e. if -q has a
+ * similar rotation as q.
+ */
+IK_PUBLIC_API void
+quat_normalise_sign(ik_real* q1);
+
+C_HEADER_END
+
+#endif /* QUATERNION_H */

+ 227 - 0
Source/ThirdParty/ik/ik/include/ik/solver.h

@@ -0,0 +1,227 @@
+#ifndef IK_SOLVER_H
+#define IK_SOLVER_H
+
+#include "ik/gen/config.h"
+#include "ik/pstdint.h"
+#include "ik/ordered_vector.h"
+#include "ik/vec3.h"
+#include "ik/quat.h"
+
+C_HEADER_BEGIN
+
+struct ik_effector_t;
+struct ik_node_t;
+struct ik_solver_t;
+
+typedef void (*ik_solver_destroy_func)(struct ik_solver_t*);
+typedef int (*ik_solver_rebuild_data_func)(struct ik_solver_t*);
+typedef void (*ik_solver_recalculate_segment_lengths_func)(struct ik_solver_t*);
+typedef int (*ik_solver_solve_func)(struct ik_solver_t*);
+
+typedef void (*ik_solver_apply_constraint_cb_func)(struct ik_node_t*);
+typedef void (*ik_solver_apply_result_cb_func)(struct ik_node_t*);
+
+enum solver_algorithm_e
+{
+    SOLVER_FABRIK
+    /* TODO Not implemented
+    SOLVER_JACOBIAN_INVERSE,
+    SOLVER_JACOBIAN_TRANSPOSE */
+};
+
+enum solver_flags_e
+{
+    /*!
+     * @brief Causes the root node in the tree to be excluded from the list of
+     * nodes to solve for. It won't be affected by the solver, but it may still
+     * be passed through to the result callback function.
+     */
+    SOLVER_EXCLUDE_ROOT                   = 0x01,
+
+    /*!
+     * @brief This is a post-processing step which can optionally be enabled.
+     * Causes the correct global angles to be calculated for each node in the
+     * solved tree. The results can be retrieved from node->solved_rotation.
+     * This should definitely be enabled for skinned models.
+     */
+    SOLVER_CALCULATE_FINAL_ROTATIONS      = 0x02,
+
+    /* (not yet implemented)
+     * Calculate node angles for each iteration, which may be useful in the
+     * solver->apply_constraint callback function.
+     */
+    SOLVER_CALCULATE_CONSTRAINT_ROTATIONS = 0x04,
+
+    SOLVER_CALCULATE_TARGET_ROTATIONS     = 0x08,
+
+    /*!
+     * @brief The solver will not reset the solved data to its initial state
+     * before solving. The result is a more "continuous" or "ongoing" solution
+     * to the tree, because it will use the previous solved tree as a bases for
+     * solving the next tree.
+     */
+    SOLVER_SKIP_RESET                     = 0x10,
+
+    /*!
+     * @brief The solver will not call the solver->apply_result callback
+     * function after solving. The results are still calculated. This is useful
+     * if you wish to delay the point at which the solved data is applied. You
+     * can later call ik_solver_iterate_tree() to initiate calls to the
+     * callback function.
+     */
+    SOLVER_SKIP_APPLY                     = 0x20
+};
+
+/*!
+ * @brief This is a base struct for all solvers.
+ */
+#define SOLVER_DATA_HEAD                                             \
+    ik_solver_apply_constraint_cb_func apply_constraint;             \
+    ik_solver_apply_result_cb_func     apply_result;                 \
+                                                                     \
+    int32_t                            max_iterations;               \
+    float                              tolerance;                    \
+    uint8_t                            flags;                        \
+                                                                     \
+    /* Derived structure callbacks */                                \
+    ik_solver_destroy_func             destroy;                      \
+    ik_solver_rebuild_data_func        rebuild_data;                 \
+    ik_solver_recalculate_segment_lengths_func recalculate_segment_lengths; \
+    ik_solver_solve_func               solve;                        \
+                                                                     \
+    struct ordered_vector_t            effector_nodes_list;          \
+    struct ik_node_t*                  tree;
+struct ik_solver_t
+{
+    SOLVER_DATA_HEAD
+};
+
+/*!
+ * @brief Allocates a new solver object according to the specified algorithm.
+ *
+ * Once the solver is created, you can configure the solver to enable/disable
+ * various features depending on your needs.
+ *
+ * The following attributes can be changed at any point.
+ *  + solver->apply_result
+ *       This is the main mechanism with which to obtain the solved data.
+ *       Assign a callback function here and it will be called for every node
+ *       in the tree when a new target position/rotation has been calculated.
+ *       You can use the node->user_data attribute to store external node
+ *       specific data, which can be accessed again the in callback function.
+ *  + solver->max_iterations
+ *       Specifies the maximum number of iterations. The more iterations, the
+ *       more exact the result will be. The default value for the FABRIK solver
+ *       is 20, but you can get away with values as low as 5.
+ *  + solver->tolerance
+ *       This value can be changed at any point. Specifies the acceptable
+ *       distance each effector needs to be to its target position. The solver
+ *       will stop iterating if the effectors are within this distance. The
+ *       default value is 1e-3. Recommended values are 100th of your world
+ *       unit.
+ *  + solver->flags
+ *       Changes the behaviour of the solver. See the enum solver_flags_e for
+ *       more information.
+ *
+ * The following attributes can be accessed (read from) but should not be
+ * modified.
+ *  + solver->tree
+ *       The tree to be solved. You may modify the nodes in the tree.
+ *       @note If you add/remove nodes or if you add/remove effectors, you
+ *       must call ik_solver_rebuild_data() so the internal solver structures
+ *       are updated. Failing to do so may cause segfaults. If you're just
+ *       updating positions/rotations or any of the other public data then
+ *       there is no need to rebuild data.
+ *  + solver->effector_nodes_list
+ *       A vector containing pointers to nodes in the tree which have an
+ *       effector attached to them. You may not modify this list, but you may
+ *       iterate it.
+ * @param[in] algorithm The algorithm to use. Currently, only FABRIK is
+ * supported.
+ */
+IK_PUBLIC_API struct ik_solver_t*
+ik_solver_create(enum solver_algorithm_e algorithm);
+
+/*!
+ * @brief Destroys the solver and all nodes/effectors that are part of the
+ * solver. Any pointers to tree nodes are invalid after this function returns.
+ */
+IK_PUBLIC_API void
+ik_solver_destroy(struct ik_solver_t* solver);
+
+/*!
+ * @brief Sets the tree to solve. The solver takes ownership of the tree, so
+ * destroying the solver will destroy all nodes in the tree. Note that you will
+ * have to call ik_solver_rebuild_data() before being able to solve it. If the
+ * solver already has a tree, then said tree will be destroyed.
+ */
+IK_PUBLIC_API void
+ik_solver_set_tree(struct ik_solver_t* solver, struct ik_node_t* root);
+
+/*!
+ * @brief The solver releases any references to a previously set tree and
+ * returns the root node of said tree. Any proceeding calls that involve the
+ * tree (e.g. solve or rebuild) will have no effect until a new tree is set.
+ * @return If the solver has no tree then NULL is returned.
+ */
+IK_PUBLIC_API struct ik_node_t*
+ik_solver_unlink_tree(struct ik_solver_t* solver);
+
+/*!
+ * @brief The solver releases any references to a previously set tree and
+ * destroys it.
+ */
+IK_PUBLIC_API void
+ik_solver_destroy_tree(struct ik_solver_t* solver);
+
+/*!
+ * @brief Causes the set tree to be processed into more optimal data structures
+ * for solving. Must be called before ik_solver_solve().
+ * @note Needs to be called whenever the tree changes in any way. I.e. if you
+ * remove nodes or add nodes, or if you remove effectors or add effectors,
+ * you must call this again before calling the solver.
+ */
+IK_PUBLIC_API int
+ik_solver_rebuild_data(struct ik_solver_t* solver);
+
+/*!
+ * @brief Unusual, but if you have a tree with translational motions such that
+ * the distances between nodes changes (perhaps a slider?), you can call this
+ * to re-calculate the segment lengths after assigning new positions to the
+ * nodes.
+ * @note This function gets called by ik_solver_rebuild_data().
+ */
+IK_PUBLIC_API void
+ik_solver_recalculate_segment_lengths(struct ik_solver_t* solver);
+
+/*!
+ * @brief Solves the IK problem. The node solutions will be provided via a
+ * callback function, which can be registered to the solver by assigning it to
+ * solver->apply_result.
+ */
+IK_PUBLIC_API int
+ik_solver_solve(struct ik_solver_t* solver);
+
+/*!
+ * @brief Iterates all nodes in the internal tree, breadth first, and calls the
+ * solver->apply_result callback function for every node.
+ *
+ * This gets called automatically for you by ik_solver_solve() if
+ * SOLVER_SKIP_APPLY is **not** set. This function could also be used to reset
+ * your own scene graph to its initial state by reading the node->position and
+ * node->rotation properties.
+ */
+IK_PUBLIC_API void
+ik_solver_iterate_tree(struct ik_solver_t* solver);
+
+/*!
+ * @brief Sets the solved positions and rotations equal to the original
+ * positions and rotations for every node in the tree. The solver will call
+ * this automatically if SOLVER_SKIP_RESET is **not** set.
+ */
+IK_PUBLIC_API void
+ik_solver_reset_solved_data(struct ik_solver_t* solver);
+
+C_HEADER_END
+
+#endif /* IK_SOLVER_H */

+ 39 - 0
Source/ThirdParty/ik/ik/include/ik/solver_FABRIK.h

@@ -0,0 +1,39 @@
+#ifndef IK_SOLVER_FABRIK_H
+#define IK_SOLVER_FABRIK_H
+
+#include "ik/gen/config.h"
+#include "ik/ordered_vector.h"
+#include "ik/solver.h"
+
+C_HEADER_BEGIN
+
+struct chain_t
+{
+    struct ordered_vector_t nodes;    /* list of node_t* references */
+    struct ordered_vector_t children; /* list of chain_t objects */
+};
+
+struct fabrik_t
+{
+    SOLVER_DATA_HEAD
+    struct chain_t* chain_tree;
+};
+
+struct ik_solver_t*
+solver_FABRIK_create(void);
+
+void
+solver_FABRIK_destroy(struct ik_solver_t* solver);
+
+int
+solver_FABRIK_rebuild_data(struct ik_solver_t* solver);
+
+void
+solver_FABRIK_recalculate_segment_lengths(struct ik_solver_t* solver);
+
+int
+solver_FABRIK_solve(struct ik_solver_t* solver);
+
+C_HEADER_END
+
+#endif /* IK_SOLVER_FABRIK_H */

+ 13 - 0
Source/ThirdParty/ik/ik/include/ik/solver_jacobian_inverse.h

@@ -0,0 +1,13 @@
+#ifndef IK_SOLVER_JACOBIAN_INVERSE_H
+#define IK_SOLVER_JACOBIAN_INVERSE_H
+
+#include "ik/gen/config.h"
+
+C_HEADER_BEGIN
+
+char
+ik_solve_jacobian_inverse(void);
+
+C_HEADER_END
+
+#endif /* IK_SOLVER_JACOBIAN_INVERSE_H */

+ 13 - 0
Source/ThirdParty/ik/ik/include/ik/solver_jacobian_transpose.h

@@ -0,0 +1,13 @@
+#ifndef IK_SOLVER_JACOBIAN_TRANSPOSE_H
+#define IK_SOLVER_JACOBIAN_TRANSPOSE_H
+
+#include "ik/gen/config.h"
+
+C_HEADER_BEGIN
+
+char
+ik_solve_jacobian_transpose(void);
+
+C_HEADER_END
+
+#endif /* IK_SOLVER_JACOBIAN_TRANSPOSE_H */

+ 50 - 0
Source/ThirdParty/ik/ik/include/ik/vec3.h

@@ -0,0 +1,50 @@
+#ifndef VEC3_H
+#define VEC3_H
+
+#include "ik/gen/config.h"
+
+C_HEADER_BEGIN
+
+typedef union vec3_t
+{
+    struct {
+        ik_real x;
+        ik_real y;
+        ik_real z;
+    } v;
+    ik_real f[3];
+} vec3_t;
+
+IK_PUBLIC_API void
+vec3_set_zero(ik_real* v);
+
+IK_PUBLIC_API void
+vec3_add_vec3(ik_real* v1, const ik_real* v2);
+
+IK_PUBLIC_API void
+vec3_sub_vec3(ik_real* v1, const ik_real* v2);
+
+IK_PUBLIC_API void
+vec3_mul_scalar(ik_real* v1, ik_real scalar);
+
+IK_PUBLIC_API void
+vec3_div_scalar(ik_real* v, ik_real scalar);
+
+IK_PUBLIC_API ik_real
+vec3_length_squared(const ik_real* v);
+
+IK_PUBLIC_API ik_real
+vec3_length(const ik_real* v);
+
+IK_PUBLIC_API void
+vec3_normalise(ik_real* v);
+
+IK_PUBLIC_API ik_real
+vec3_dot(const ik_real* v1, const ik_real* v2);
+
+IK_PUBLIC_API void
+vec3_cross(ik_real* v1, const ik_real* v2);
+
+C_HEADER_END
+
+#endif /* VEC3_H */

+ 253 - 0
Source/ThirdParty/ik/ik/src/bst_vector.c

@@ -0,0 +1,253 @@
+#include "ik/bst_vector.h"
+#include "ik/memory.h"
+#include <assert.h>
+#include <string.h>
+
+const uint32_t BST_VECTOR_INVALID_HASH = (uint32_t)-1;
+
+/* ------------------------------------------------------------------------- */
+struct bstv_t*
+bstv_create(void)
+{
+    struct bstv_t* bstv;
+    if(!(bstv = (struct bstv_t*)MALLOC(sizeof *bstv)))
+        return NULL;
+    bstv_construct(bstv);
+    return bstv;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+bstv_construct(struct bstv_t* bstv)
+{
+    assert(bstv);
+    ordered_vector_construct(&bstv->vector, sizeof(struct bstv_hash_value_t));
+}
+
+/* ------------------------------------------------------------------------- */
+void
+bstv_destroy(struct bstv_t* bstv)
+{
+    assert(bstv);
+    bstv_clear_free(bstv);
+    FREE(bstv);
+}
+
+/* ------------------------------------------------------------------------- */
+/* algorithm taken from GNU GCC stdlibc++'s lower_bound function, line 2121 in stl_algo.h */
+/* https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a02014.html */
+static struct bstv_hash_value_t*
+bstv_find_lower_bound(const struct bstv_t* bstv, uint32_t hash)
+{
+    uint32_t half;
+    struct bstv_hash_value_t* middle;
+    struct bstv_hash_value_t* data;
+    uint32_t len;
+
+    assert(bstv);
+
+    data = (struct bstv_hash_value_t*)bstv->vector.data;
+    len = bstv->vector.count;
+
+    /* if the vector has no data, return NULL */
+    if(!len)
+        return NULL;
+
+    while(len > 0)
+    {
+        half = len >> 1;
+        middle = data + half;
+        if(middle->hash < hash)
+        {
+            data = middle;
+            ++data;
+            len = len - half - 1;
+        }
+        else
+            len = half;
+    }
+
+    /* if "data" is pointing outside of the valid elements in the vector, also return NULL */
+    if((intptr_t)data >= (intptr_t)bstv->vector.data + (intptr_t)bstv->vector.count * (intptr_t)bstv->vector.element_size)
+        return NULL;
+    else
+        return data;
+}
+
+/* ------------------------------------------------------------------------- */
+int
+bstv_insert(struct bstv_t* bstv, uint32_t hash, void* value)
+{
+    struct bstv_hash_value_t* emplaced_data;
+    struct bstv_hash_value_t* lower_bound;
+
+    assert(bstv);
+
+    /* don't insert reserved hashes */
+    if(hash == BST_VECTOR_INVALID_HASH)
+        return -1;
+
+    /* lookup location in bstv to insert */
+    lower_bound = bstv_find_lower_bound(bstv, hash);
+    if(lower_bound && lower_bound->hash == hash)
+        return 1;
+
+    /* either push back or insert, depending on whether there is already data
+     * in the bstv */
+    if(!lower_bound)
+        emplaced_data = (struct bstv_hash_value_t*)ordered_vector_push_emplace(&bstv->vector);
+    else
+        emplaced_data = ordered_vector_insert_emplace(&bstv->vector,
+                          lower_bound - (struct bstv_hash_value_t*)bstv->vector.data);
+
+    if(!emplaced_data)
+        return -1;
+
+    memset(emplaced_data, 0, sizeof *emplaced_data);
+    emplaced_data->hash = hash;
+    emplaced_data->value = value;
+
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+bstv_set(struct bstv_t* bstv, uint32_t hash, void* value)
+{
+    struct bstv_hash_value_t* data;
+
+    assert(bstv);
+
+    data = bstv_find_lower_bound(bstv, hash);
+    if(data && data->hash == hash)
+        data->value = value;
+}
+
+/* ------------------------------------------------------------------------- */
+void*
+bstv_find(const struct bstv_t* bstv, uint32_t hash)
+{
+    void** result = bstv_find_ptr(bstv, hash);
+    return result == NULL ? NULL : *result;
+}
+
+/* ------------------------------------------------------------------------- */
+void**
+bstv_find_ptr(const struct bstv_t* bstv, uint32_t hash)
+{
+    struct bstv_hash_value_t* data;
+
+    assert(bstv);
+
+    data = bstv_find_lower_bound(bstv, hash);
+    if(!data || data->hash != hash)
+        return NULL;
+    return &data->value;
+}
+
+/* ------------------------------------------------------------------------- */
+uint32_t
+bstv_find_element(const struct bstv_t* bstv, const void* value)
+{
+    assert(bstv);
+
+    ORDERED_VECTOR_FOR_EACH(&bstv->vector, struct bstv_hash_value_t, kv)
+        if(kv->value == value)
+            return kv->hash;
+    ORDERED_VECTOR_END_EACH
+    return BST_VECTOR_INVALID_HASH;
+}
+
+/* ------------------------------------------------------------------------- */
+void*
+bstv_get_any_element(const struct bstv_t* bstv)
+{
+    struct bstv_hash_value_t* kv;
+    assert(bstv);
+    kv = (struct bstv_hash_value_t*)ordered_vector_back(&bstv->vector);
+    if(kv)
+        return kv->value;
+    return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+int
+bstv_hash_exists(struct bstv_t* bstv, uint32_t hash)
+{
+    struct bstv_hash_value_t* data;
+
+    assert(bstv);
+
+    data = bstv_find_lower_bound(bstv, hash);
+    if(data && data->hash == hash)
+        return 0;
+    return -1;
+}
+
+/* ------------------------------------------------------------------------- */
+uint32_t
+bstv_find_unused_hash(struct bstv_t* bstv)
+{
+    uint32_t i = 0;
+
+    assert(bstv);
+
+    BSTV_FOR_EACH(bstv, void, key, value)
+        if(i != key)
+            break;
+        ++i;
+    BSTV_END_EACH
+    return i;
+}
+
+/* ------------------------------------------------------------------------- */
+void*
+bstv_erase(struct bstv_t* bstv, uint32_t hash)
+{
+    void* value;
+    struct bstv_hash_value_t* data;
+
+    assert(bstv);
+
+    data = bstv_find_lower_bound(bstv, hash);
+    if(!data || data->hash != hash)
+        return NULL;
+
+    value = data->value;
+    ordered_vector_erase_element(&bstv->vector, (DATA_POINTER_TYPE*)data);
+    return value;
+}
+
+/* ------------------------------------------------------------------------- */
+void*
+bstv_erase_element(struct bstv_t* bstv, void* value)
+{
+    void* data;
+    uint32_t hash;
+
+    assert(bstv);
+
+    hash = bstv_find_element(bstv, value);
+    if(hash == BST_VECTOR_INVALID_HASH)
+        return NULL;
+
+    data = bstv_find_lower_bound(bstv, hash);
+    ordered_vector_erase_element(&bstv->vector, (DATA_POINTER_TYPE*)data);
+
+    return value;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+bstv_clear(struct bstv_t* bstv)
+{
+    assert(bstv);
+    ordered_vector_clear(&bstv->vector);
+}
+
+/* ------------------------------------------------------------------------- */
+void bstv_clear_free(struct bstv_t* bstv)
+{
+    assert(bstv);
+    ordered_vector_clear_free(&bstv->vector);
+}

+ 44 - 0
Source/ThirdParty/ik/ik/src/effector.c

@@ -0,0 +1,44 @@
+#include "ik/effector.h"
+#include "ik/memory.h"
+#include "ik/node.h"
+#include <string.h>
+
+/* ------------------------------------------------------------------------- */
+struct ik_effector_t*
+ik_effector_create(void)
+{
+    struct ik_effector_t* effector = (struct ik_effector_t*)MALLOC(sizeof *effector);
+    if(effector == NULL)
+        return NULL;
+
+    ik_effector_construct(effector);
+    return effector;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_effector_construct(struct ik_effector_t* effector)
+{
+    memset(effector, 0, sizeof *effector);
+    quat_set_identity(effector->target_rotation.f);
+    effector->weight = 0;
+    effector->rotation_weight = 1.0;
+    effector->rotation_decay = 0.25;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_effector_destroy(struct ik_effector_t* effector)
+{
+    FREE(effector);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+effector_attach(struct ik_effector_t* effector, struct ik_node_t* node)
+{
+    if(node->effector != NULL)
+        ik_effector_destroy(node->effector);
+
+    node->effector = effector;
+}

+ 97 - 0
Source/ThirdParty/ik/ik/src/log.c

@@ -0,0 +1,97 @@
+#include "ik/log.h"
+#include "ik/memory.h"
+#include "ik/ordered_vector.h"
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+static struct log_t
+{
+    struct ordered_vector_t listeners; /* list of ik_log_cb_func */
+    struct ordered_vector_t message_buffer;
+}* g_log = NULL;
+
+static void log_stdout_callback(const char* msg)
+{
+    puts(msg);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_log_init(enum ik_log_e options)
+{
+    if(g_log != NULL)
+        return;
+
+    g_log = (struct log_t*)MALLOC(sizeof *g_log);
+    if(g_log == NULL)
+        return;
+
+    ordered_vector_construct(&g_log->listeners, sizeof(ik_log_cb_func));
+    ordered_vector_construct(&g_log->message_buffer, sizeof(char));
+
+    if(options == IK_LOG_STDOUT)
+        ik_log_register_listener(log_stdout_callback);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_log_deinit(void)
+{
+    if(g_log == NULL)
+        return;
+
+    ordered_vector_clear_free(&g_log->message_buffer);
+    ordered_vector_clear_free(&g_log->listeners);
+    FREE(g_log);
+    g_log = NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_log_register_listener(ik_log_cb_func callback)
+{
+    if(g_log != NULL)
+        ordered_vector_push(&g_log->listeners, &callback);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_log_unregister_listener(ik_log_cb_func callback)
+{
+    if(g_log == NULL)
+        return;
+
+    ORDERED_VECTOR_FOR_EACH(&g_log->listeners, ik_log_cb_func, registered_callback)
+        if(callback == *registered_callback)
+        {
+            ordered_vector_erase_element(&g_log->listeners, registered_callback);
+            return;
+        }
+    ORDERED_VECTOR_END_EACH
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_log_message(const char* fmt, ...)
+{
+    va_list va;
+    uintptr_t msg_len;
+
+    if(g_log == NULL)
+        return;
+
+    va_start(va, fmt);
+    msg_len = vsnprintf(NULL, 0, fmt, va);
+    va_end(va);
+
+    if(ordered_vector_resize(&g_log->message_buffer, (msg_len + 1) * sizeof(char)) < 0)
+        return;
+    va_start(va, fmt);
+    vsprintf((char*)g_log->message_buffer.data, fmt, va);
+    va_end(va);
+
+    ORDERED_VECTOR_FOR_EACH(&g_log->listeners, ik_log_cb_func, callback)
+        (*callback)((char*)g_log->message_buffer.data);
+    ORDERED_VECTOR_END_EACH
+}

+ 281 - 0
Source/ThirdParty/ik/ik/src/memory.c

@@ -0,0 +1,281 @@
+#include "ik/memory.h"
+#include "ik/bst_vector.h"
+#include "ik/backtrace.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#define BACKTRACE_OMIT_COUNT 2
+
+#if IK_MEMORY_DEBUGGING == ON
+static uintptr_t g_allocations = 0;
+static uintptr_t d_deg_allocations = 0;
+static uintptr_t g_ignore_bstv_malloc = 0;
+static struct bstv_t report;
+
+struct report_info_t
+{
+    uintptr_t location;
+    uintptr_t size;
+#   if IK_MEMORY_BACKTRACE == ON
+    int backtrace_size;
+    char** backtrace;
+#   endif
+};
+
+/* ------------------------------------------------------------------------- */
+void
+ik_memory_init(void)
+{
+    g_allocations = 0;
+    d_deg_allocations = 0;
+
+    /*
+     * Init bst vector of report objects and force it to allocate by adding
+     * and removing one item. This fixes a bug where the number of memory leaks
+     * would be wrong in the case of MALLOC() never being called.
+     */
+    g_ignore_bstv_malloc = 1;
+        bstv_construct(&report);
+        bstv_insert(&report, 0, NULL); bstv_erase(&report, 0);
+    g_ignore_bstv_malloc = 0;
+}
+
+/* ------------------------------------------------------------------------- */
+void*
+malloc_wrapper(intptr_t size)
+{
+    void* p = NULL;
+    struct report_info_t* info = NULL;
+
+    /* breaking from this will clean up and return NULL */
+    for(;;)
+    {
+        /* allocate */
+        p = malloc(size);
+        if(p)
+            ++g_allocations;
+        else
+            break;
+
+        /*
+        * Record allocation info. Call to bstv may allocate memory,
+        * so set flag to ignore the call to malloc() when inserting.
+        */
+        if(!g_ignore_bstv_malloc)
+        {
+            g_ignore_bstv_malloc = 1;
+            info = (struct report_info_t*)malloc(sizeof(struct report_info_t));
+            if(!info)
+            {
+                fprintf(stderr, "[memory] ERROR: malloc() for report_info_t failed"
+                    " -- not enough memory.\n");
+                g_ignore_bstv_malloc = 0;
+                break;
+            }
+
+            /* record the location and size of the allocation */
+            info->location = (uintptr_t)p;
+            info->size = size;
+
+            /* if enabled, generate a backtrace so we know where memory leaks
+            * occurred */
+#   if IK_MEMORY_BACKTRACE == ON
+            if(!(info->backtrace = get_backtrace(&info->backtrace_size)))
+                fprintf(stderr, "[memory] WARNING: Failed to generate backtrace\n");
+#   endif
+
+            /* insert into bstv */
+            if(bstv_insert(&report, (uintptr_t)p, info) == 1)
+            {
+                fprintf(stderr,
+                "[memory] WARNING: Hash collision occurred when inserting\n"
+                "into memory report bstv. On 64-bit systems the pointers are\n"
+                "rounded down to 32-bit unsigned integers, so even though\n"
+                "it's rare, collisions can happen.\n\n"
+                "The matching call to FREE() will generate a warning saying\n"
+                "something is being freed that was never allocated. This is to\n"
+                "be expected and can be ignored.\n");
+#   if IK_MEMORY_BACKTRACE == ON
+                {
+                    char** bt;
+                    int bt_size, i;
+                    if((bt = get_backtrace(&bt_size)))
+                    {
+                        printf("  backtrace to where malloc() was called:\n");
+                        for(i = 0; i < bt_size; ++i)
+                            printf("      %s\n", bt[i]);
+                        printf("  -----------------------------------------\n");
+                        free(bt);
+                    }
+                    else
+                        fprintf(stderr, "[memory] WARNING: Failed to generate backtrace\n");
+                }
+#   endif
+            }
+            g_ignore_bstv_malloc = 0;
+        }
+
+        /* success */
+        return p;
+    }
+
+    /* failure */
+    if(p)
+    {
+        free(p);
+        --g_allocations;
+    }
+
+    if(info)
+    {
+#   if IK_MEMORY_BACKTRACE == ON
+        if(info->backtrace)
+            free(info->backtrace);
+#   endif
+        free(info);
+    }
+
+    return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+free_wrapper(void* ptr)
+{
+    /* find matching allocation and remove from bstv */
+    if(!g_ignore_bstv_malloc)
+    {
+        struct report_info_t* info = (struct report_info_t*)bstv_erase(&report, (uintptr_t)ptr);
+        if(info)
+        {
+#   if IK_MEMORY_BACKTRACE == ON
+            if(info->backtrace)
+                free(info->backtrace);
+            else
+                fprintf(stderr, "[memory] WARNING: free(): Allocation didn't "
+                    "have a backtrace (it was NULL)\n");
+#   endif
+            free(info);
+        }
+        else
+        {
+#   if IK_MEMORY_BACKTRACE == ON
+            char** bt;
+            int bt_size, i;
+            fprintf(stderr, "  -----------------------------------------\n");
+#   endif
+            fprintf(stderr, "  WARNING: Freeing something that was never allocated\n");
+#   if IK_MEMORY_BACKTRACE == ON
+            if((bt = get_backtrace(&bt_size)))
+            {
+                fprintf(stderr, "  backtrace to where free() was called:\n");
+                for(i = 0; i < bt_size; ++i)
+                    fprintf(stderr, "      %s\n", bt[i]);
+                fprintf(stderr, "  -----------------------------------------\n");
+                free(bt);
+            }
+            else
+                fprintf(stderr, "[memory] WARNING: Failed to generate backtrace\n");
+#   endif
+        }
+    }
+
+    if(ptr)
+    {
+        ++d_deg_allocations;
+        free(ptr);
+    }
+    else
+        fprintf(stderr, "Warning: free(NULL)\n");
+}
+
+/* ------------------------------------------------------------------------- */
+uintptr_t
+ik_memory_deinit(void)
+{
+    uintptr_t leaks;
+
+    --g_allocations; /* this is the single allocation still held by the report vector */
+
+    printf("=========================================\n");
+    printf("Inverse Kinematics Memory Report\n");
+    printf("=========================================\n");
+
+    /* report details on any g_allocations that were not de-allocated */
+    if(report.vector.count != 0)
+    {
+        BSTV_FOR_EACH(&report, struct report_info_t, key, info)
+
+            printf("  un-freed memory at %p, size %p\n", (void*)info->location, (void*)info->size);
+            mutated_string_and_hex_dump((void*)info->location, info->size);
+
+#   if IK_MEMORY_BACKTRACE == ON
+            printf("  Backtrace to where malloc() was called:\n");
+            {
+                intptr_t i;
+                for(i = BACKTRACE_OMIT_COUNT; i < info->backtrace_size; ++i)
+                    printf("      %s\n", info->backtrace[i]);
+            }
+            free(info->backtrace); /* this was allocated when malloc() was called */
+            printf("  -----------------------------------------\n");
+#   endif
+            free(info);
+
+        BSTV_END_EACH
+
+        printf("=========================================\n");
+    }
+
+    /* overall report */
+    leaks = (g_allocations > d_deg_allocations ? g_allocations - d_deg_allocations : d_deg_allocations - g_allocations);
+    printf("allocations: %lu\n", g_allocations);
+    printf("deallocations: %lu\n", d_deg_allocations);
+    printf("memory leaks: %lu\n", leaks);
+    printf("=========================================\n");
+
+    ++g_allocations; /* this is the single allocation still held by the report vector */
+    g_ignore_bstv_malloc = 1;
+    bstv_clear_free(&report);
+
+    return leaks;
+}
+
+#else /* IK_MEMORY_DEBUGGING */
+
+void ik_memory_init(void) {}
+uintptr_t ik_memory_deinit(void) { return 0; }
+
+#endif /* IK_MEMORY_DEBUGGING */
+
+/* ------------------------------------------------------------------------- */
+void
+mutated_string_and_hex_dump(void* data, intptr_t length_in_bytes)
+{
+    char* dump;
+    intptr_t i;
+
+    /* allocate and copy data into new buffer */
+    if(!(dump = malloc(length_in_bytes + 1)))
+    {
+        fprintf(stderr, "[memory] WARNING: Failed to malloc() space for dump\n");
+        return;
+    }
+    memcpy(dump, data, length_in_bytes);
+    dump[length_in_bytes] = '\0';
+
+    /* mutate null terminators into dots */
+    for(i = 0; i != length_in_bytes; ++i)
+        if(dump[i] == '\0')
+            dump[i] = '.';
+
+    /* dump */
+    printf("  mutated string dump: %s\n", dump);
+    printf("  hex dump: ");
+    for(i = 0; i != length_in_bytes; ++i)
+        printf(" %02x", (unsigned char)dump[i]);
+    printf("\n");
+
+    free(dump);
+}

+ 160 - 0
Source/ThirdParty/ik/ik/src/node.c

@@ -0,0 +1,160 @@
+#include "ik/effector.h"
+#include "ik/log.h"
+#include "ik/memory.h"
+#include "ik/node.h"
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+
+/* ------------------------------------------------------------------------- */
+struct ik_node_t*
+ik_node_create(uint32_t guid)
+{
+    struct ik_node_t* node = (struct ik_node_t*)MALLOC(sizeof *node);
+    if(node == NULL)
+        return NULL;
+
+    ik_node_construct(node, guid);
+    return node;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_node_construct(struct ik_node_t* node, uint32_t guid)
+{
+    memset(node, 0, sizeof *node);
+    bstv_construct(&node->children);
+    quat_set_identity(node->rotation.f);
+    quat_set_identity(node->solved_rotation.f);
+    node->guid = guid;
+}
+
+/* ------------------------------------------------------------------------- */
+static void
+ik_node_destroy_recursive(struct ik_node_t* node);
+static void
+ik_node_destruct_recursive(struct ik_node_t* node)
+{
+    BSTV_FOR_EACH(&node->children, struct ik_node_t, guid, child)
+        ik_node_destroy_recursive(child);
+    BSTV_END_EACH
+
+    if(node->effector)
+        ik_effector_destroy(node->effector);
+
+    bstv_clear_free(&node->children);
+}
+void
+ik_node_destruct(struct ik_node_t* node)
+{
+    BSTV_FOR_EACH(&node->children, struct ik_node_t, guid, child)
+        ik_node_destroy_recursive(child);
+    BSTV_END_EACH
+
+    if(node->effector)
+        ik_effector_destroy(node->effector);
+
+    ik_node_unlink(node);
+    bstv_clear_free(&node->children);
+}
+
+/* ------------------------------------------------------------------------- */
+static void
+ik_node_destroy_recursive(struct ik_node_t* node)
+{
+    ik_node_destruct_recursive(node);
+    FREE(node);
+}
+void
+ik_node_destroy(struct ik_node_t* node)
+{
+    ik_node_destruct(node);
+    FREE(node);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_node_add_child(struct ik_node_t* node, struct ik_node_t* child)
+{
+    child->parent = node;
+    bstv_insert(&node->children, child->guid, child);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_node_unlink(struct ik_node_t* node)
+{
+    if(node->parent == NULL)
+        return;
+
+    assert(node == bstv_erase(&node->parent->children, node->guid));
+    node->parent = NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+struct ik_node_t*
+ik_node_find_child(struct ik_node_t* node, uint32_t guid)
+{
+    struct ik_node_t* found = bstv_find(&node->children, guid);
+    if(found != NULL)
+        return found;
+
+    if(node->guid == guid)
+        return node;
+
+    BSTV_FOR_EACH(&node->children, struct ik_node_t, child_guid, child)
+        found = ik_node_find_child(child, guid);
+        if(found != NULL)
+            return found;
+    BSTV_END_EACH
+
+    return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_node_attach_effector(struct ik_node_t* node, struct ik_effector_t* effector)
+{
+    node->effector = effector;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_node_destroy_effector(struct ik_node_t* node)
+{
+    if(node->effector == NULL)
+        return;
+    ik_effector_destroy(node->effector);
+    node->effector = NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+static void
+recursively_dump_dot(FILE* fp, struct ik_node_t* node)
+{
+    if(node->effector != NULL)
+        fprintf(fp, "    %d [color=\"1.0 0.5 1.0\"];\n", node->guid);
+
+    BSTV_FOR_EACH(&node->children, struct ik_node_t, guid, child)
+        fprintf(fp, "    %d -- %d;\n", node->guid, guid);
+        recursively_dump_dot(fp, child);
+    BSTV_END_EACH
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_node_dump_to_dot(struct ik_node_t* node, const char* file_name)
+{
+    FILE* fp = fopen(file_name, "w");
+    if(fp == NULL)
+    {
+        ik_log_message("Failed to open file %s", file_name);
+        return;
+    }
+
+    fprintf(fp, "graph graphname {\n");
+    recursively_dump_dot(fp, node);
+    fprintf(fp, "}\n");
+
+    fclose(fp);
+}

+ 351 - 0
Source/ThirdParty/ik/ik/src/ordered_vector.c

@@ -0,0 +1,351 @@
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "ik/ordered_vector.h"
+#include "ik/memory.h"
+
+/* ----------------------------------------------------------------------------
+ * Static functions
+ * ------------------------------------------------------------------------- */
+
+/*!
+ * @brief Expands the underlying memory.
+ *
+ * This implementation will expand the memory by a factor of 2 each time this
+ * is called. All elements are copied into the new section of memory.
+ * @param[in] insertion_index Set to -1 if no space should be made for element
+ * insertion. Otherwise this parameter specifies the index of the element to
+ * "evade" when re-allocating all other elements.
+ * @param[in] target_size If set to 0, target size is calculated automatically.
+ * Otherwise the vector will expand to the specified target size.
+ * @note No checks are performed to make sure the target size is large enough.
+ */
+static int
+ordered_vector_expand(struct ordered_vector_t *vector,
+                      uintptr_t insertion_index,
+                      uint32_t target_size);
+
+/* ----------------------------------------------------------------------------
+ * Exported functions
+ * ------------------------------------------------------------------------- */
+struct ordered_vector_t*
+ordered_vector_create(const uint32_t element_size)
+{
+    struct ordered_vector_t* vector;
+    if(!(vector = (struct ordered_vector_t*)MALLOC(sizeof(struct ordered_vector_t))))
+        return NULL;
+    ordered_vector_construct(vector, element_size);
+    return vector;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ordered_vector_construct(struct ordered_vector_t* vector, const uint32_t element_size)
+{
+    assert(vector);
+    memset(vector, 0, sizeof(struct ordered_vector_t));
+    vector->element_size = element_size;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ordered_vector_destroy(struct ordered_vector_t* vector)
+{
+    assert(vector);
+    ordered_vector_clear_free(vector);
+    FREE(vector);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ordered_vector_clear(struct ordered_vector_t* vector)
+{
+    assert(vector);
+    /*
+     * No need to free or overwrite existing memory, just reset the counter
+     * and let future insertions overwrite
+     */
+    vector->count = 0;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ordered_vector_clear_free(struct ordered_vector_t* vector)
+{
+    assert(vector);
+
+    if(vector->data)
+        FREE(vector->data);
+
+    vector->data = NULL;
+    vector->count = 0;
+    vector->capacity = 0;
+}
+
+/* ------------------------------------------------------------------------- */
+int
+ordered_vector_resize(struct ordered_vector_t* vector, uint32_t size)
+{
+    int result = 0;
+
+    assert(vector);
+
+    if(vector->count < size)
+        result = ordered_vector_expand(vector, -1, size);
+    vector->count = size;
+
+    return result;
+}
+
+/* ------------------------------------------------------------------------- */
+void*
+ordered_vector_push_emplace(struct ordered_vector_t* vector)
+{
+    void* data;
+
+    assert(vector);
+
+    if(vector->count == vector->capacity)
+        if(ordered_vector_expand(vector, -1, 0) < 0)
+            return NULL;
+    data = vector->data + (vector->element_size * vector->count);
+    ++(vector->count);
+    return data;
+}
+
+/* ------------------------------------------------------------------------- */
+int
+ordered_vector_push(struct ordered_vector_t* vector, void* data)
+{
+    void* emplaced;
+
+    assert(vector);
+    assert(data);
+
+    emplaced = ordered_vector_push_emplace(vector);
+    if(!emplaced)
+        return -1;
+    memcpy(emplaced, data, vector->element_size);
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+int
+ordered_vector_push_vector(struct ordered_vector_t* vector, struct ordered_vector_t* source_vector)
+{
+    assert(vector);
+    assert(source_vector);
+
+    /* make sure element sizes are equal */
+    if(vector->element_size != source_vector->element_size)
+        return -1;
+
+    /* make sure there's enough space in the target vector */
+    if(vector->count + source_vector->count > vector->capacity)
+        if(ordered_vector_expand(vector, -1, vector->count + source_vector->count) < 0)
+            return -1;
+
+    /* copy data */
+    memcpy(vector->data + (vector->count * vector->element_size),
+           source_vector->data,
+           source_vector->count * vector->element_size);
+    vector->count += source_vector->count;
+
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+void*
+ordered_vector_pop(struct ordered_vector_t* vector)
+{
+    assert(vector);
+
+    if(!vector->count)
+        return NULL;
+
+    --(vector->count);
+    return vector->data + (vector->element_size * vector->count);
+}
+
+/* ------------------------------------------------------------------------- */
+void*
+ordered_vector_back(const struct ordered_vector_t* vector)
+{
+    assert(vector);
+
+    if(!vector->count)
+        return NULL;
+
+    return vector->data + (vector->element_size * (vector->count - 1));
+}
+
+/* ------------------------------------------------------------------------- */
+void*
+ordered_vector_insert_emplace(struct ordered_vector_t* vector, uint32_t index)
+{
+    uint32_t offset;
+
+    assert(vector);
+
+    /*
+     * Normally the last valid index is (capacity-1), but in this case it's valid
+     * because it's possible the user will want to insert at the very end of
+     * the vector.
+     */
+    if(index > vector->count)
+        return NULL;
+
+    /* re-allocate? */
+    if(vector->count == vector->capacity)
+    {
+        if(ordered_vector_expand(vector, index, 0) < 0)
+            return NULL;
+    }
+    else
+    {
+        /* shift all elements up by one to make space for insertion */
+        uint32_t total_size = vector->count * vector->element_size;
+        offset = vector->element_size * index;
+        memmove((void*)((intptr_t)vector->data + offset + vector->element_size),
+                (void*)((intptr_t)vector->data + offset),
+                total_size - offset);
+    }
+
+    /* return pointer to memory of new element */
+    ++vector->count;
+    return (void*)(vector->data + index * vector->element_size);
+}
+
+/* ------------------------------------------------------------------------- */
+int
+ordered_vector_insert(struct ordered_vector_t* vector, uint32_t index, void* data)
+{
+    void* emplaced;
+
+    assert(vector);
+    assert(data);
+
+    emplaced = ordered_vector_insert_emplace(vector, index);
+    if(!emplaced)
+        return -1;
+    memcpy(emplaced, data, vector->element_size);
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ordered_vector_erase_index(struct ordered_vector_t* vector, uint32_t index)
+{
+    assert(vector);
+
+    if(index >= vector->count)
+        return;
+
+    if(index == vector->count - 1)
+        /* last element doesn't require memory shifting, just pop it */
+        ordered_vector_pop(vector);
+    else
+    {
+        /* shift memory right after the specified element down by one element */
+        uint32_t offset = vector->element_size * index;  /* offset to the element being erased in bytes */
+        uint32_t total_size = vector->element_size * vector->count; /* total current size in bytes */
+        memmove((void*)((intptr_t)vector->data + offset),   /* target is to overwrite the element specified by index */
+                (void*)((intptr_t)vector->data + offset + vector->element_size),    /* copy beginning from one element ahead of element to be erased */
+                total_size - offset - vector->element_size);     /* copying number of elements after element to be erased */
+        --vector->count;
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ordered_vector_erase_element(struct ordered_vector_t* vector, void* element)
+{
+    uintptr_t last_element;
+
+    assert(vector);
+    last_element = (uintptr_t)vector->data + (vector->count-1) * vector->element_size;
+    assert(element);
+    assert((uintptr_t)element >= (uintptr_t)vector->data);
+    assert((uintptr_t)element <= (uintptr_t)last_element);
+
+    if(element != (void*)last_element)
+    {
+        memmove(element,    /* target is to overwrite the element */
+                (void*)((uintptr_t)element + vector->element_size), /* read everything from next element */
+                last_element - (uintptr_t)element);
+    }
+    --vector->count;
+}
+
+/* ------------------------------------------------------------------------- */
+void*
+ordered_vector_get_element(struct ordered_vector_t* vector, uint32_t index)
+{
+    assert(vector);
+
+    if(index >= vector->count)
+        return NULL;
+    return vector->data + (vector->element_size * index);
+}
+
+/* ----------------------------------------------------------------------------
+ * Static functions
+ * ------------------------------------------------------------------------- */
+static int
+ordered_vector_expand(struct ordered_vector_t *vector,
+                      uintptr_t insertion_index,
+                      uint32_t target_count)
+{
+    uintptr_t new_count;
+    DATA_POINTER_TYPE* old_data;
+    DATA_POINTER_TYPE* new_data;
+
+    /* expand by factor 2, or adopt target count if it is not 0 */
+    if(target_count)
+        new_count = target_count;
+    else
+        new_count = vector->capacity << 1;
+
+    /*
+     * If vector hasn't allocated anything yet, just allocated the requested
+     * amount of memory and return immediately.
+     */
+    if(!vector->data)
+    {
+        new_count = (new_count == 0 ? 2 : new_count);
+        vector->data = MALLOC(new_count * vector->element_size);
+        if(!vector->data)
+            return -1;
+        vector->capacity = new_count;
+        return 0;
+    }
+
+    /* prepare for reallocating data */
+    old_data = vector->data;
+    new_data = (DATA_POINTER_TYPE*)MALLOC(new_count * vector->element_size);
+    if(!new_data)
+        return -1;
+
+    /* if no insertion index is required, copy all data to new memory */
+    if(insertion_index == (uintptr_t)-1 || insertion_index >= new_count)
+        memcpy(new_data, old_data, vector->count * vector->element_size);
+
+    /* keep space for one element at the insertion index */
+    else
+    {
+        /* copy old data up until right before insertion offset */
+        uint32_t offset = vector->element_size * insertion_index;
+        uint32_t total_size = vector->element_size * vector->count;
+        memcpy(new_data, old_data, offset);
+        /* copy the remaining amount of old data shifted one element ahead */
+        memcpy((void*)((intptr_t)new_data + offset + vector->element_size),
+               (void*)((intptr_t)old_data + offset),
+               total_size - offset);
+    }
+
+    vector->data = new_data;
+    vector->capacity = new_count;
+    FREE(old_data);
+
+    return 0;
+}

+ 15 - 0
Source/ThirdParty/ik/ik/src/platform/linux/backtrace_linux.c

@@ -0,0 +1,15 @@
+#include "ik/backtrace.h"
+#include <execinfo.h>
+
+/* ------------------------------------------------------------------------- */
+char**
+get_backtrace(int* size)
+{
+    void* array[BACKTRACE_SIZE];
+    char** strings;
+
+    *size = backtrace(array, BACKTRACE_SIZE);
+    strings = backtrace_symbols(array, *size);
+
+    return strings;
+}

+ 147 - 0
Source/ThirdParty/ik/ik/src/quat.c

@@ -0,0 +1,147 @@
+#include "ik/quat.h"
+#include <math.h>
+#include <string.h>
+
+/* ------------------------------------------------------------------------- */
+void
+quat_set_identity(ik_real* q)
+{
+    memset(q, 0, sizeof(ik_real) * 3);
+    q[3] = 1;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+quat_add_quat(ik_real* q1, const ik_real* q2)
+{
+    q1[0] += q2[0];
+    q1[1] += q2[1];
+    q1[2] += q2[2];
+    q1[3] += q2[3];
+}
+
+/* ------------------------------------------------------------------------- */
+ik_real
+quat_mag(const ik_real* q)
+{
+    return sqrt(q[3]*q[3] + q[2]*q[2] + q[1]*q[1] + q[0]*q[0]);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+quat_conj(ik_real* q)
+{
+    q[0] = -q[0];
+    q[1] = -q[1];
+    q[2] = -q[2];
+}
+
+/* ------------------------------------------------------------------------- */
+void
+quat_invert_sign(ik_real* q)
+{
+    q[0] = -q[0];
+    q[1] = -q[1];
+    q[2] = -q[2];
+    q[3] = -q[3];
+}
+
+
+/* ------------------------------------------------------------------------- */
+void
+quat_normalise(ik_real* q)
+{
+    ik_real mag = quat_mag(q);
+    if(mag != 0.0)
+        mag = 1.0 / mag;
+    q[0] *= mag;
+    q[1] *= mag;
+    q[2] *= mag;
+    q[3] *= mag;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+quat_mul_quat(ik_real* q1, const ik_real* q2)
+{
+    ik_real v1[3];
+    ik_real v2[3];
+    memcpy(v1, q1, sizeof(ik_real) * 3);
+    memcpy(v2, q2, sizeof(ik_real) * 3);
+
+    vec3_mul_scalar(v1, q2[3]);
+    vec3_mul_scalar(v2, q1[3]);
+    q1[3] = q1[3]*q2[3] - vec3_dot(q1, q2);
+    vec3_cross(q1, q2);
+    vec3_add_vec3(q1, v1);
+    vec3_add_vec3(q1, v2);
+
+    quat_normalise(q1);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+quat_mul_scalar(ik_real* q, ik_real scalar)
+{
+    q[0] *= scalar;
+    q[1] *= scalar;
+    q[2] *= scalar;
+    q[3] *= scalar;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+quat_div_scalar(ik_real* q, ik_real scalar)
+{
+    if(scalar == 0.0)
+        quat_set_identity(q);
+    else
+    {
+        ik_real rec = 1.0 / scalar;
+        q[0] *= rec;
+        q[1] *= rec;
+        q[2] *= rec;
+        q[3] *= rec;
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+ik_real
+quat_dot(ik_real* q1, const ik_real* q2)
+{
+    return q1[0] * q2[0] +
+           q1[1] * q2[1] +
+           q1[2] * q2[2] +
+           q1[3] * q2[3];
+}
+
+/* ------------------------------------------------------------------------- */
+void
+quat_rotate_vec(ik_real* v, const ik_real* q)
+{
+    /* P' = RPR' */
+    quat_t result;
+    quat_t conj;
+    quat_t point;
+
+    memcpy(point.f, v, sizeof(ik_real) * 3);
+    point.q.w = 0.0;
+
+    conj = *(quat_t*)q;
+    quat_conj(conj.f);
+
+    result = *(quat_t*)q;
+    quat_mul_quat(result.f, point.f);
+    quat_mul_quat(result.f, conj.f);
+    memcpy(v, result.f, sizeof(ik_real) * 3);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+quat_normalise_sign(ik_real* q1)
+{
+    quat_t unit = {{0, 0, 0, 1}};
+    ik_real dot = quat_dot(q1, unit.f);
+    if(dot < 0.0)
+        quat_invert_sign(q1);
+}

+ 181 - 0
Source/ThirdParty/ik/ik/src/solver.c

@@ -0,0 +1,181 @@
+#include "ik/effector.h"
+#include "ik/log.h"
+#include "ik/memory.h"
+#include "ik/node.h"
+#include "ik/solver.h"
+#include "ik/solver_FABRIK.h"
+#include "ik/solver_jacobian_inverse.h"
+#include "ik/solver_jacobian_transpose.h"
+
+static int
+recursive_get_all_effector_nodes(struct ik_node_t* node, struct ordered_vector_t* effector_nodes_list);
+
+/* ------------------------------------------------------------------------- */
+struct ik_solver_t*
+ik_solver_create(enum solver_algorithm_e algorithm)
+{
+    struct ik_solver_t* solver = NULL;
+
+    switch(algorithm)
+    {
+    case SOLVER_FABRIK:
+        solver = (struct ik_solver_t*)solver_FABRIK_create();
+        break;
+
+    /*case SOLVER_JACOBIAN_INVERSE:
+    case SOLVER_JACOBIAN_TRANSPOSE:
+        break;*/
+    }
+
+    if(solver == NULL)
+        return NULL;
+
+    ordered_vector_construct(&solver->effector_nodes_list, sizeof(struct ik_node_t*));
+
+    return solver;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_solver_destroy(struct ik_solver_t* solver)
+{
+    if(solver->tree)
+        ik_node_destroy(solver->tree);
+
+    ordered_vector_clear_free(&solver->effector_nodes_list);
+
+    solver->destroy(solver);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_solver_set_tree(struct ik_solver_t* solver, struct ik_node_t* root)
+{
+    ik_solver_destroy_tree(solver);
+    solver->tree = root;
+}
+
+/* ------------------------------------------------------------------------- */
+struct ik_node_t*
+ik_solver_unlink_tree(struct ik_solver_t* solver)
+{
+    struct ik_node_t* root = solver->tree;
+    if(root == NULL)
+        return NULL;
+    solver->tree = NULL;
+
+    /*
+     * Effectors are owned by the nodes, but we need to release references to
+     * them.
+     */
+    ordered_vector_clear(&solver->effector_nodes_list);
+
+    return root;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_solver_destroy_tree(struct ik_solver_t* solver)
+{
+    struct ik_node_t* root;
+    if((root = ik_solver_unlink_tree(solver)) == NULL)
+        return;
+    ik_node_destroy(root);
+}
+
+/* ------------------------------------------------------------------------- */
+int
+ik_solver_rebuild_data(struct ik_solver_t* solver)
+{
+    /* If the solver has no tree, then there's nothing to do */
+    if(solver->tree == NULL)
+    {
+        ik_log_message("No tree to work with. Did you forget to set the tree with ik_solver_set_tree()?");
+        return -1;
+    }
+
+    /*
+     * Traverse the entire tree and generate a list of the effectors. This
+     * makes the process of building the chain list for FABRIK much easier.
+     */
+    ik_log_message("Rebuilding effector nodes list");
+    ordered_vector_clear(&solver->effector_nodes_list);
+    if(recursive_get_all_effector_nodes(solver->tree,
+                                        &solver->effector_nodes_list) < 0)
+    {
+        ik_log_message("Ran out of memory while building the effector nodes list");
+        return -1;
+    }
+
+    return solver->rebuild_data(solver);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+ik_solver_recalculate_segment_lengths(struct ik_solver_t* solver)
+{
+    solver->recalculate_segment_lengths(solver);
+}
+
+/* ------------------------------------------------------------------------- */
+int
+ik_solver_solve(struct ik_solver_t* solver)
+{
+    return solver->solve(solver);
+}
+
+/* ------------------------------------------------------------------------- */
+static void
+iterate_tree_recursive(struct ik_solver_t* solver, struct ik_node_t* node)
+{
+    if(solver->apply_result)
+        solver->apply_result(node);
+
+    BSTV_FOR_EACH(&node->children, struct ik_node_t, guid, child)
+        iterate_tree_recursive(solver, child);
+    BSTV_END_EACH
+}
+void
+ik_solver_iterate_tree(struct ik_solver_t* solver)
+{
+    if(solver->tree == NULL)
+        return;
+
+    iterate_tree_recursive(solver, solver->tree);
+}
+
+/* ------------------------------------------------------------------------- */
+static void
+reset_solved_data_recursive(struct ik_node_t* node)
+{
+    node->solved_position = node->position;
+    node->solved_rotation = node->rotation;
+
+    BSTV_FOR_EACH(&node->children, struct ik_node_t, guid, child)
+        reset_solved_data_recursive(child);
+    BSTV_END_EACH
+}
+void
+ik_solver_reset_solved_data(struct ik_solver_t* solver)
+{
+    if(solver->tree == NULL)
+        return;
+
+    reset_solved_data_recursive(solver->tree);
+}
+
+/* ------------------------------------------------------------------------- */
+static int
+recursive_get_all_effector_nodes(struct ik_node_t* node, struct ordered_vector_t* effector_nodes_list)
+{
+    if(node->effector != NULL)
+        if(ordered_vector_push(effector_nodes_list, &node) < 0)
+            return -1;
+
+    BSTV_FOR_EACH(&node->children, struct ik_node_t, guid, child)
+        if(recursive_get_all_effector_nodes(child, effector_nodes_list) < 0)
+            return -1;
+    BSTV_END_EACH
+
+    return 0;
+}

+ 814 - 0
Source/ThirdParty/ik/ik/src/solver_FABRIK.c

@@ -0,0 +1,814 @@
+#include "ik/bst_vector.h"
+#include "ik/effector.h"
+#include "ik/log.h"
+#include "ik/memory.h"
+#include "ik/node.h"
+#include "ik/solver_FABRIK.h"
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+enum node_marking_e
+{
+    MARK_NONE = 0,
+    MARK_SPLIT,
+    MARK_SECTION
+};
+
+struct effector_data_t
+{
+    vec3_t target_direction;
+    ik_real rotation_weight;
+    ik_real rotation_weight_decay;
+};
+
+static void
+chain_construct(struct chain_t* chain);
+static void
+chain_clear_free(struct chain_t* chain);
+static void
+chain_destruct(struct chain_t* chain);
+static void
+calculate_segment_lengths_recursive(struct chain_t* chain);
+
+/* ------------------------------------------------------------------------- */
+static void
+chain_construct(struct chain_t* chain)
+{
+    ordered_vector_construct(&chain->nodes, sizeof(struct ik_node_t*));
+    ordered_vector_construct(&chain->children, sizeof(struct chain_t));
+}
+
+/* ------------------------------------------------------------------------- */
+static void
+chain_clear_free(struct chain_t* chain)
+{
+    ORDERED_VECTOR_FOR_EACH(&chain->children, struct chain_t, child_chain)
+        chain_destruct(child_chain);
+    ORDERED_VECTOR_END_EACH
+    ordered_vector_clear_free(&chain->children);
+    ordered_vector_clear_free(&chain->nodes);
+}
+
+/* ------------------------------------------------------------------------- */
+static void
+chain_destruct(struct chain_t* chain)
+{
+    chain_clear_free(chain);
+}
+
+/*!
+ * @brief Breaks down the relevant nodes of the scene graph into a list of
+ * chains. FABRIK can then more efficiently solve each chain individually.
+ *
+ * A "sub-base joint" is a node in the scene graph where at least two end
+ * effector nodes eventually join together. FABRIK only works on single
+ * chains of joints at a time. The end position of every sub-base joint is
+ * the average of the resulting multiple positions after running FABRIK on
+ * each chain. Said average position becomes the new target position for
+ * the next chain connected to it.
+ *
+ * This algorithm finds all sub-base joints and generates chains between
+ * base, sub-base joints, and end effectors. These chains are inserted into
+ * the chain list. The order is such that iterating the list from the
+ * beginning results in traversing the sub-base nodes breadth-last. This is
+ * important.
+ *
+ * @note Effectors that are deactivated or invalid are ignored in this search.
+ * So even though a node might share two effectors, if one of them is
+ * deactivated, then the node is no longer considered a sub-base node.
+ */
+static int
+rebuild_chain_tree(struct fabrik_t* solver);
+
+/* ------------------------------------------------------------------------- */
+struct ik_solver_t*
+solver_FABRIK_create(void)
+{
+    struct fabrik_t* solver;
+
+    ik_log_message("Creating FABRIK solver");
+
+    solver = (struct fabrik_t*)MALLOC(sizeof *solver);
+    if(solver == NULL)
+    {
+        ik_log_message("Ran out of memory in solver_FABRIK_create()");
+        goto alloc_solver_filed;
+    }
+    memset(solver, 0, sizeof *solver);
+
+    solver->destroy = solver_FABRIK_destroy;
+    solver->rebuild_data = solver_FABRIK_rebuild_data;
+    solver->recalculate_segment_lengths = solver_FABRIK_recalculate_segment_lengths;
+    solver->solve = solver_FABRIK_solve;
+
+    solver->max_iterations = 20;
+    solver->tolerance = 1e-3;
+
+    solver->chain_tree = (struct chain_t*)MALLOC(sizeof(struct chain_t));
+    if(solver->chain_tree == NULL)
+    {
+        ik_log_message("Ran out of memory in solver_FABRIK_create()");
+        goto alloc_chain_tree_failed;
+    }
+    chain_construct(solver->chain_tree);
+
+    return (struct ik_solver_t*)solver;
+
+    alloc_chain_tree_failed : FREE(solver);
+    alloc_solver_filed      : return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+solver_FABRIK_destroy(struct ik_solver_t* solver)
+{
+    struct fabrik_t* fabrik;
+
+    ik_log_message("Destroying FABRIK solver");
+
+    fabrik = (struct fabrik_t*)solver;
+    chain_destruct(fabrik->chain_tree);
+    FREE(fabrik->chain_tree);
+    FREE(solver);
+}
+
+/* ------------------------------------------------------------------------- */
+int
+solver_FABRIK_rebuild_data(struct ik_solver_t* solver)
+{
+    return rebuild_chain_tree((struct fabrik_t*)solver);
+}
+
+/* ------------------------------------------------------------------------- */
+static void
+determine_target_data_from_effector(struct chain_t* chain, vec3_t* target_position)
+{
+    /* Extract effector node and get its effector object */
+    struct ik_node_t* effector_node;
+    struct ik_effector_t* effector;
+    assert(ordered_vector_count(&chain->nodes) > 1);
+    effector_node = *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, 0);
+    assert(effector_node->effector != NULL);
+    effector = effector_node->effector;
+
+    /* lerp using effector weight to get actual target position */
+    *target_position = effector->target_position;
+    vec3_sub_vec3(target_position->f, effector_node->position.f);
+    vec3_mul_scalar(target_position->f, effector->weight);
+    vec3_add_vec3(target_position->f, effector_node->position.f);
+
+    /* Fancy algorithm using nlerp, makes transitions look more natural */
+    if(effector->flags & EFFECTOR_WEIGHT_NLERP && effector->weight < 1.0)
+    {
+        ik_real distance_to_target;
+        vec3_t base_to_effector;
+        vec3_t base_to_target;
+        struct ik_node_t* base_node;
+
+        /* Need distance from base node to target and base to effector node */
+        base_node = *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes,
+                ordered_vector_count(&chain->nodes) - 1);
+        base_to_effector = effector_node->position;
+        base_to_target = effector->target_position;
+        vec3_sub_vec3(base_to_effector.f, base_node->position.f);
+        vec3_sub_vec3(base_to_target.f, base_node->position.f);
+
+        /* The effective distance is a lerp between these two distances */
+        distance_to_target = vec3_length(base_to_target.f) * effector->weight;
+        distance_to_target += vec3_length(base_to_effector.f) * (1.0 - effector->weight);
+
+        /* nlerp the target position by pinning it to the base node */
+        vec3_sub_vec3(target_position->f, base_node->position.f);
+        vec3_normalise(target_position->f);
+        vec3_mul_scalar(target_position->f, distance_to_target);
+        vec3_add_vec3(target_position->f, base_node->position.f);
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+static vec3_t
+solve_chain_forwards_with_target_rotation(struct chain_t* chain, struct effector_data_t* effector_data)
+{
+    int node_count, node_idx;
+    int average_count;
+    vec3_t target_position = {{0, 0, 0}};
+
+    /*
+     * Target position is the average of all solved child chain base positions.
+     */
+    average_count = 0;
+    ORDERED_VECTOR_FOR_EACH(&chain->children, struct chain_t, child)
+        struct effector_data_t child_effector_data;
+        vec3_t child_base_position = solve_chain_forwards_with_target_rotation(child, &child_effector_data);
+        vec3_add_vec3(target_position.f, child_base_position.f);
+        vec3_add_vec3(effector_data->target_direction.f, child_effector_data.target_direction.f);
+        effector_data->rotation_weight += child_effector_data.rotation_weight;
+        effector_data->rotation_weight_decay += child_effector_data.rotation_weight_decay;
+        ++average_count;
+    ORDERED_VECTOR_END_EACH
+
+    /*
+     * If there are no child chains, then the first node in the chain must
+     * contain an effector. The target position is the effector's target
+     * position. Otherwise, average the data we've been accumulating from the
+     * child chains.
+     */
+    if(average_count == 0)
+    {
+        struct ik_node_t* effector_node = *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, 0);
+        struct ik_effector_t* effector = effector_node->effector;
+        determine_target_data_from_effector(chain, &target_position);
+
+        effector_data->rotation_weight = effector->rotation_weight;
+        effector_data->rotation_weight_decay = effector->rotation_decay;
+        /* TODO This "global direction" could be made configurable if needed */
+        effector_data->target_direction.v.x = 0.0;
+        effector_data->target_direction.v.y = 0.0;
+        effector_data->target_direction.v.z = 1.0;
+        quat_rotate_vec(effector_data->target_direction.f, effector->target_rotation.f);
+
+    }
+    else
+    {
+        ik_real div = 1.0 / average_count;
+        vec3_mul_scalar(target_position.f, div);
+        vec3_mul_scalar(effector_data->target_direction.f, div);
+        effector_data->rotation_weight *= div;
+        effector_data->rotation_weight_decay *= div;
+    }
+
+    /*
+     * Iterate through each segment and apply the FABRIK algorithm.
+     */
+    node_count = ordered_vector_count(&chain->nodes);
+    for(node_idx = 0; node_idx < node_count - 1; ++node_idx)
+    {
+        struct ik_node_t* child_node  = *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, node_idx + 0);
+        struct ik_node_t* parent_node = *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, node_idx + 1);
+
+        /* move node to target */
+        child_node->solved_position = target_position;
+
+        /* lerp direction vector and segment vector */
+        vec3_sub_vec3(target_position.f, effector_data->target_direction.f);
+        vec3_sub_vec3(target_position.f, parent_node->solved_position.f);
+        vec3_mul_scalar(target_position.f, effector_data->rotation_weight);
+        vec3_add_vec3(target_position.f, parent_node->solved_position.f);
+
+        vec3_sub_vec3(target_position.f, child_node->solved_position.f);
+        vec3_normalise(target_position.f);
+        vec3_mul_scalar(target_position.f, child_node->segment_length);
+        vec3_add_vec3(target_position.f, child_node->solved_position.f);
+
+        effector_data->rotation_weight *= effector_data->rotation_weight_decay;
+    }
+
+    return target_position;
+}
+
+/* ------------------------------------------------------------------------- */
+static vec3_t
+solve_chain_forwards(struct chain_t* chain)
+{
+    int node_count, node_idx;
+    int average_count;
+    vec3_t target_position = {{0, 0, 0}};
+
+    /*
+     * Target position is the average of all solved child chain base positions.
+     */
+    average_count = 0;
+    ORDERED_VECTOR_FOR_EACH(&chain->children, struct chain_t, child)
+        vec3_t child_base_position = solve_chain_forwards(child);
+        vec3_add_vec3(target_position.f, child_base_position.f);
+        ++average_count;
+    ORDERED_VECTOR_END_EACH
+
+    /*
+     * If there are no child chains, then the first node in the chain must
+     * contain an effector. The target position is the effector's target
+     * position. Otherwise, average the data we've been accumulating from the
+     * child chains.
+     */
+    if(average_count == 0)
+        determine_target_data_from_effector(chain, &target_position);
+    else
+        vec3_div_scalar(target_position.f, average_count);
+
+    /*
+     * Iterate through each segment and apply the FABRIK algorithm.
+     */
+    node_count = ordered_vector_count(&chain->nodes);
+    for(node_idx = 0; node_idx < node_count - 1; ++node_idx)
+    {
+        struct ik_node_t* child_node  = *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, node_idx + 0);
+        struct ik_node_t* parent_node = *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, node_idx + 1);
+
+        /* move node to target */
+        child_node->solved_position = target_position;
+
+        /* point segment to previous node and set target position to its end */
+        vec3_sub_vec3(target_position.f, parent_node->solved_position.f); /* parent points to child */
+        vec3_normalise(target_position.f);                                /* normalise */
+        vec3_mul_scalar(target_position.f, -child_node->segment_length);  /* child points to parent */
+        vec3_add_vec3(target_position.f, child_node->solved_position.f);  /* attach to child -- this is the new target */
+    }
+
+    return target_position;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+solve_chain_backwards(struct chain_t* chain, vec3_t target_position)
+{
+    int node_idx = ordered_vector_count(&chain->nodes) - 1;
+
+    /*
+     * The base node must be set to the target position before iterating.
+     */
+    if(node_idx > 1)
+    {
+        struct ik_node_t* base_node = *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, node_idx);
+        base_node->solved_position = target_position;
+    }
+
+    /*
+     * Iterate through each segment the other way around and apply the FABRIK
+     * algorithm.
+     */
+    while(node_idx-- > 0)
+    {
+        struct ik_node_t* child_node  = *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, node_idx + 0);
+        struct ik_node_t* parent_node = *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, node_idx + 1);
+
+        /* point segment to child node and set target position to its beginning */
+        vec3_sub_vec3(target_position.f, child_node->solved_position.f);  /* child points to parent */
+        vec3_normalise(target_position.f);                                /* normalise */
+        vec3_mul_scalar(target_position.f, -child_node->segment_length);  /* parent points to child */
+        vec3_add_vec3(target_position.f, parent_node->solved_position.f); /* attach to parent -- this is the new target */
+
+        /* move node to target */
+        child_node->solved_position = target_position;
+    }
+
+    ORDERED_VECTOR_FOR_EACH(&chain->children, struct chain_t, child)
+        solve_chain_backwards(child, target_position);
+    ORDERED_VECTOR_END_EACH
+}
+
+/* ------------------------------------------------------------------------- */
+static void
+calculate_global_rotations(struct chain_t* chain)
+{
+    /*
+     * Calculates the "global" (world) angles of each joint and writes them to
+     * each node->solved_rotation slot.
+     *
+     * The angle between the original and solved segments are calculated using
+     * standard vector math (dot product). The axis of rotation is calculated
+     * with the cross product. From this data, a quaternion is constructed,
+     * describing this delta rotation. Finally, in order to make the rotations
+     * global instead of relative, the delta rotation is multiplied with
+     * node->rotation, which should be a quaternion describing the node's
+     * global rotation in the unsolved tree.
+     *
+     * The rotation of the base joint in the chain is returned so it can be
+     * averaged by parent chains.
+     */
+
+    int node_idx;
+    int average_count;
+    quat_t average_rotation = {{0, 0, 0, 0}};
+
+    /* Recursive into children chains */
+    average_count = 0;
+    ORDERED_VECTOR_FOR_EACH(&chain->children, struct chain_t, child)
+        quat_t rotation;
+        calculate_global_rotations(child);
+
+        /* Note: All chains that aren't the root chain *MUST* have at least two nodes */
+        assert(ordered_vector_count(&child->nodes) >= 2);
+        rotation = (*(struct ik_node_t**)
+                ordered_vector_get_element(&child->nodes,
+                    ordered_vector_count(&child->nodes) - 1))->solved_rotation;
+
+        /*
+         * Averaging quaternions taken from here
+         * http://wiki.unity3d.com/index.php/Averaging_Quaternions_and_Vectors
+         */
+        quat_normalise_sign(rotation.f);
+        quat_add_quat(average_rotation.f, rotation.f);
+        ++average_count;
+    ORDERED_VECTOR_END_EACH
+
+    /*
+     * Assuming there was more than 1 child chain and assuming we aren't the
+     * root node, then the child chains we just iterated must share the same
+     * base node as our tip node. Average the accumulated quaternion and set
+     * this node's correct solved rotation.
+     */
+    if(average_count > 0 && ordered_vector_count(&chain->nodes) != 0)
+    {
+        quat_div_scalar(average_rotation.f, average_count);
+        quat_normalise(average_rotation.f);
+        (*(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, 0))
+            ->solved_rotation = average_rotation;
+    }
+
+    node_idx = ordered_vector_count(&chain->nodes) - 1;
+    while(node_idx-- > 0)
+    {
+        ik_real cos_a, sin_a, angle, denominator;
+        struct ik_node_t* child_node  = *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, node_idx + 0);
+        struct ik_node_t* parent_node = *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, node_idx + 1);
+
+        /* calculate vectors for original and solved segments */
+        vec3_t segment_original = child_node->position;
+        vec3_t segment_solved   = child_node->solved_position;
+        vec3_sub_vec3(segment_original.f, parent_node->position.f);
+        vec3_sub_vec3(segment_solved.f, parent_node->solved_position.f);
+
+        /*
+         * Calculate angle between original segment and solved segment. If the
+         * angle is 0 or 180, we don't do anything. The solved rotation is
+         * initially set to the original rotation.
+         */
+        denominator = 1.0 / vec3_length(segment_original.f) / vec3_length(segment_solved.f);
+        cos_a = vec3_dot(segment_original.f, segment_solved.f) * denominator;
+        if(cos_a >= -1.0 && cos_a <= 1.0)
+        {
+            /* calculate axis of rotation and write it to the quaternion's vector section */
+            parent_node->solved_rotation.vw.v = segment_original;
+            vec3_cross(parent_node->solved_rotation.vw.v.f, segment_solved.f);
+            vec3_normalise(parent_node->solved_rotation.f);
+
+            /* quaternion's vector needs to be weighted with sin_a */
+            angle = acos(cos_a);
+            cos_a = cos(angle * 0.5);
+            sin_a = sin(angle * 0.5);
+            vec3_mul_scalar(parent_node->solved_rotation.f, sin_a);
+            parent_node->solved_rotation.q.w = cos_a;
+
+            /*
+             * Apply initial global rotation to calculated delta rotation to
+             * obtain the solved global rotation.
+             */
+            quat_mul_quat(parent_node->solved_rotation.f, parent_node->rotation.f);
+        }
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+int
+solver_FABRIK_solve(struct ik_solver_t* solver)
+{
+    struct fabrik_t* fabrik = (struct fabrik_t*)solver;
+    int iteration;
+    ik_real tolerance_squared = solver->tolerance * solver->tolerance;
+
+    if(!(solver->flags & SOLVER_SKIP_RESET))
+        ik_solver_reset_solved_data(solver);
+
+    iteration = solver->max_iterations;
+    while(iteration--)
+    {
+        vec3_t root_position;
+        struct effector_data_t effector_data;
+
+        ORDERED_VECTOR_FOR_EACH(&fabrik->chain_tree->children, struct chain_t, chain)
+
+            assert(ordered_vector_count(&chain->nodes) > 1);
+            root_position = (*(struct ik_node_t**)ordered_vector_get_element(&chain->nodes,
+                    ordered_vector_count(&chain->nodes) - 1))->position;
+
+            if(solver->flags & SOLVER_CALCULATE_TARGET_ROTATIONS)
+                solve_chain_forwards_with_target_rotation(chain, &effector_data);
+            else
+                solve_chain_forwards(chain);
+
+            solve_chain_backwards(chain, root_position);
+        ORDERED_VECTOR_END_EACH
+
+        ORDERED_VECTOR_FOR_EACH(&fabrik->effector_nodes_list, struct ik_node_t*, pnode)
+            vec3_t diff = (*pnode)->solved_position;
+            vec3_sub_vec3(diff.f, (*pnode)->effector->target_position.f);
+            if(vec3_length_squared(diff.f) > tolerance_squared)
+                goto continue_iterating;
+        ORDERED_VECTOR_END_EACH
+
+        break;
+        continue_iterating:;
+    }
+
+    if(solver->flags & SOLVER_CALCULATE_FINAL_ROTATIONS)
+        calculate_global_rotations(fabrik->chain_tree);
+
+    if(!(solver->flags & SOLVER_SKIP_APPLY))
+        ik_solver_iterate_tree(solver);
+
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+solver_FABRIK_recalculate_segment_lengths(struct ik_solver_t* solver)
+{
+    struct fabrik_t* fabrik = (struct fabrik_t*)solver;
+    calculate_segment_lengths_recursive(fabrik->chain_tree);
+}
+
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------------- */
+int
+mark_involved_nodes(struct fabrik_t* solver, struct bstv_t* involved_nodes)
+{
+    /*
+     * Traverse the chain of parents starting at each effector node and ending
+     * at the root node of the tree and mark every node on the way. Each
+     * effector specifies a maximum chain length, which means it's possible
+     * that we won't hit the root node.
+     */
+    struct ordered_vector_t* effector_nodes_list = &solver->effector_nodes_list;
+    ORDERED_VECTOR_FOR_EACH(effector_nodes_list, struct ik_node_t*, p_effector_node)
+
+        /*
+         * Set up chain length counter. If the chain length is 0 then it is
+         * infinitely long. Set the counter to -1 in this case to skip the
+         * escape condition.
+         */
+        int chain_length_counter;
+        struct ik_node_t* node = *p_effector_node;
+        assert(node->effector != NULL);
+        chain_length_counter = node->effector->chain_length == 0 ? -1 : (int)node->effector->chain_length;
+
+        /*
+         * Mark nodes that are at the base of the chain differently, so the
+         * chains can be split correctly later. Section markings will overwrite
+         * break markings.
+         */
+        for(; node != NULL; node = node->parent)
+        {
+            enum node_marking_e* current_marking;
+            enum node_marking_e marking = MARK_SECTION;
+            if(chain_length_counter == 0)
+                marking = MARK_SPLIT;
+
+            current_marking = (enum node_marking_e*)bstv_find_ptr(involved_nodes, node->guid);
+            if(current_marking == NULL)
+            {
+                if(bstv_insert(involved_nodes, node->guid, (void*)(intptr_t)marking) < 0)
+                {
+                    ik_log_message("Ran out of memory while marking involved nodes");
+                    return -1;
+                }
+            }
+            else
+            {
+                if(chain_length_counter != 0)
+                    *current_marking = marking;
+            }
+
+            if(chain_length_counter-- == 0)
+                break;
+        }
+    ORDERED_VECTOR_END_EACH
+
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+static int
+recursively_build_chain_tree(struct chain_t* chain_current,
+                             struct ik_node_t* node_base,
+                             struct ik_node_t* node_current,
+                             struct bstv_t* involved_nodes)
+{
+    int marked_children_count;
+    struct ik_node_t* child_node_base = node_base;
+    struct chain_t* child_chain = chain_current;
+
+    /* can remove the mark from the set to speed up future checks */
+    enum node_marking_e marking =
+        (enum node_marking_e)(intptr_t)bstv_erase(involved_nodes, node_current->guid);
+
+    switch(marking)
+    {
+        /*
+         * If this node was marked as the base of a chain then split the chain at
+         * this point by moving the pointer to the base node down the tree to us.
+         */
+        case MARK_SPLIT:
+            child_node_base = node_current;
+            break;
+        /*
+         * If this node is not marked at all, cut off any previous chain but
+         * continue (fall through) as if a section was marked. It's possible
+         * that there are isolated chains somewhere further down the tree.
+         */
+        case MARK_NONE:
+            node_base = node_current;
+
+        case MARK_SECTION:
+            /*
+             * If the current node has at least two children marked as sections
+             * or if the current node is an effector node, but only if the base
+             * node is not equal to this node (that is, we need to avoid chains
+             * that would have less than 2 nodes), then we must also split the
+             * chain at this point.
+             */
+            marked_children_count = 0;
+            BSTV_FOR_EACH(&node_current->children, struct ik_node_t, child_guid, child)
+                if((enum node_marking_e)(intptr_t)bstv_find(involved_nodes, child_guid) == MARK_SECTION)
+                    if(++marked_children_count == 2)
+                        break;
+            BSTV_END_EACH
+            if((marked_children_count == 2 || node_current->effector != NULL) && node_current != node_base)
+            {
+                /*
+                 * Emplace a chain object into the current chain's vector of children
+                 * and initialise it.
+                 */
+                struct ik_node_t* node;
+                child_chain = ordered_vector_push_emplace(&chain_current->children);
+                if(child_chain == NULL)
+                    return -1;
+                chain_construct(child_chain);
+
+                /*
+                 * Add points to all nodes that are part of this chain into the chain's
+                 * list, starting with the end node.
+                 */
+                for(node = node_current; node != node_base; node = node->parent)
+                    ordered_vector_push(&child_chain->nodes, &node);
+                ordered_vector_push(&child_chain->nodes, &node_base);
+
+                /*
+                 * Update the base node to be this node so deeper chains are built back
+                 * to this node
+                 */
+                child_node_base = node_current;
+            }
+            break;
+    }
+
+    /* Recurse into children of the current node. */
+    BSTV_FOR_EACH(&node_current->children, struct ik_node_t, child_guid, child_node)
+        if(recursively_build_chain_tree(
+                child_chain,
+                child_node_base,
+                child_node,
+                involved_nodes) < 0)
+            return -1;
+    BSTV_END_EACH
+
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+static void
+calculate_segment_lengths_recursive(struct chain_t* chain)
+{
+    int last_idx = ordered_vector_count(&chain->nodes) - 1;
+    while(last_idx-- > 0)
+    {
+        struct ik_node_t* child_node =
+            *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, last_idx + 0);
+        struct ik_node_t* parent_node =
+            *(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, last_idx + 1);
+
+        vec3_t diff = child_node->position;
+        vec3_sub_vec3(diff.f, parent_node->position.f);
+        child_node->segment_length = vec3_length(diff.f);
+    }
+
+    ORDERED_VECTOR_FOR_EACH(&chain->children, struct chain_t, child)
+        calculate_segment_lengths_recursive(child);
+    ORDERED_VECTOR_END_EACH
+}
+
+/* ------------------------------------------------------------------------- */
+static int
+count_chains(struct chain_t* chain)
+{
+    int counter = 1;
+    ORDERED_VECTOR_FOR_EACH(&chain->children, struct chain_t, child)
+        counter += count_chains(child);
+    ORDERED_VECTOR_END_EACH
+    return counter;
+}
+
+/* ------------------------------------------------------------------------- */
+#if IK_DOT_OUTPUT == ON
+static void
+dump_chain(struct chain_t* chain, FILE* fp)
+{
+    int last_idx = ordered_vector_count(&chain->nodes) - 1;
+    if(last_idx > 0)
+    {
+        fprintf(fp, "    %d [shape=record];\n",
+            (*(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, 0))->guid);
+        fprintf(fp, "    %d [shape=record];\n",
+            (*(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, last_idx))->guid);
+    }
+
+    while(last_idx-- > 0)
+    {
+        fprintf(fp, "    %d -- %d [color=\"1.0 0.5 1.0\"];\n",
+            (*(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, last_idx + 0))->guid,
+            (*(struct ik_node_t**)ordered_vector_get_element(&chain->nodes, last_idx + 1))->guid);
+    }
+
+    ORDERED_VECTOR_FOR_EACH(&chain->children, struct chain_t, child)
+        dump_chain(child, fp);
+    ORDERED_VECTOR_END_EACH
+}
+static void
+dump_node(struct ik_node_t* node, FILE* fp)
+{
+    if(node->effector != NULL)
+        fprintf(fp, "    %d [color=\"0.6 0.5 1.0\"];\n", node->guid);
+    BSTV_FOR_EACH(&node->children, struct ik_node_t, guid, child)
+        fprintf(fp, "    %d -- %d;\n", node->guid, guid);
+        dump_node(child, fp);
+    BSTV_END_EACH
+}
+static void
+dump_to_dot(struct ik_node_t* node, struct chain_t* chain, const char* file_name)
+{
+    FILE* fp = fopen(file_name, "w");
+    if(fp == NULL)
+        return;
+
+    fprintf(fp, "graph chain_tree {\n");
+    dump_node(node, fp);
+    dump_chain(chain, fp);
+    fprintf(fp, "}\n");
+
+    fclose(fp);
+}
+#endif
+
+/* ------------------------------------------------------------------------- */
+static int
+rebuild_chain_tree(struct fabrik_t* solver)
+{
+    struct bstv_t involved_nodes;
+    int involved_nodes_count;
+#if IK_DOT_OUTPUT == ON
+    char buffer[20];
+    static int file_name_counter = 0;
+#endif
+
+    /*
+     * Build a set of all nodes that are in a direct path with all of the
+     * effectors.
+     */
+    bstv_construct(&involved_nodes);
+    if(mark_involved_nodes(solver, &involved_nodes) < 0)
+        goto mark_involved_nodes_failed;
+    involved_nodes_count = bstv_count(&involved_nodes);
+
+    /*
+     * The user can choose to set the root node as a chain terminator (default)
+     * or choose to exclude the root node, in which case each immediate child
+     * of the tree is a chain terminator. In this case we need to build the
+     * chain tree for each child individually.
+     */
+    chain_clear_free(solver->chain_tree);
+    if(solver->flags & SOLVER_EXCLUDE_ROOT)
+    {
+        BSTV_FOR_EACH(&solver->tree->children, struct ik_node_t, guid, child)
+            recursively_build_chain_tree(solver->chain_tree, child, child, &involved_nodes);
+        BSTV_END_EACH
+    }
+    else
+    {
+        recursively_build_chain_tree(solver->chain_tree, solver->tree, solver->tree, &involved_nodes);
+    }
+
+    /* Pre-compute offsets for each node in the chain tree in relation to their
+     * parents */
+    calculate_segment_lengths_recursive(solver->chain_tree);
+
+    /* DEBUG: Save chain tree to DOT */
+#if IK_DOT_OUTPUT == ON
+    sprintf(buffer, "tree%d.dot", file_name_counter++);
+    dump_to_dot(solver->tree, solver->chain_tree, buffer);
+#endif
+
+    ik_log_message("There are %d effector(s) involving %d node(s). %d chain(s) were created",
+                   ordered_vector_count(&solver->effector_nodes_list),
+                   involved_nodes_count,
+                   count_chains(solver->chain_tree) - 1); /* don't count root chain which always exists */
+
+    bstv_clear_free(&involved_nodes);
+
+    return 0;
+
+    mark_involved_nodes_failed : bstv_clear_free(&involved_nodes);
+    return -1;
+}

+ 92 - 0
Source/ThirdParty/ik/ik/src/vec3.c

@@ -0,0 +1,92 @@
+#include "ik/vec3.h"
+#include <string.h>
+#include <math.h>
+
+/* ------------------------------------------------------------------------- */
+void
+vec3_set_zero(ik_real* v)
+{
+    memset(v, 0, sizeof *v);
+}
+
+/* ------------------------------------------------------------------------- */
+void
+vec3_add_vec3(ik_real* v1, const ik_real* v2)
+{
+    v1[0] += v2[0];
+    v1[1] += v2[1];
+    v1[2] += v2[2];
+}
+
+/* ------------------------------------------------------------------------- */
+void
+vec3_sub_vec3(ik_real* v1, const ik_real* v2)
+{
+    v1[0] -= v2[0];
+    v1[1] -= v2[1];
+    v1[2] -= v2[2];
+}
+
+/* ------------------------------------------------------------------------- */
+void
+vec3_mul_scalar(ik_real* v, ik_real scalar)
+{
+    v[0] *= scalar;
+    v[1] *= scalar;
+    v[2] *= scalar;
+}
+
+/* ------------------------------------------------------------------------- */
+void
+vec3_div_scalar(ik_real* v, ik_real scalar)
+{
+    v[0] /= scalar;
+    v[1] /= scalar;
+    v[2] /= scalar;
+}
+
+/* ------------------------------------------------------------------------- */
+ik_real
+vec3_length_squared(const ik_real* v)
+{
+    return vec3_dot(v, v);
+}
+
+/* ------------------------------------------------------------------------- */
+ik_real
+vec3_length(const ik_real* v)
+{
+    return sqrt(vec3_length_squared(v));
+}
+
+/* ------------------------------------------------------------------------- */
+void
+vec3_normalise(ik_real* v)
+{
+    ik_real length = vec3_length(v);
+    if(length != 0.0)
+        length = 1.0 / length;
+    v[0] *= length;
+    v[1] *= length;
+    v[2] *= length;
+}
+
+/* ------------------------------------------------------------------------- */
+ik_real
+vec3_dot(const ik_real* v1, const ik_real* v2)
+{
+    return v1[0] * v2[0] +
+           v1[1] * v2[1] +
+           v1[2] * v2[2];
+}
+
+/* ------------------------------------------------------------------------- */
+void
+vec3_cross(ik_real* v1, const ik_real* v2)
+{
+    ik_real v1x = v1[1] * v2[2] - v2[1] * v1[2];
+    ik_real v1z = v1[0] * v2[1] - v2[0] * v1[1];
+    v1[1]       = v1[2] * v2[0] - v2[2] * v1[0];
+    v1[0] = v1x;
+    v1[2] = v1z;
+}