Introduce tiny_gltf_util.h header file which contains some useful helper/util functions.
diff --git a/examples/anim-dump/anim-dump.cc b/examples/anim-dump/anim-dump.cc
index 40537dc..022f077 100644
--- a/examples/anim-dump/anim-dump.cc
+++ b/examples/anim-dump/anim-dump.cc
@@ -1,11 +1,14 @@
 //
 // TODO(syoyo): Print extensions and extras for each glTF object.
 //
+#include "tiny_gltf_util.h"
+
 #define TINYGLTF_IMPLEMENTATION
 #define STB_IMAGE_IMPLEMENTATION
 #define STB_IMAGE_WRITE_IMPLEMENTATION
 #include "tiny_gltf.h"
 
+
 #include <cstdio>
 #include <fstream>
 #include <iostream>
@@ -16,187 +19,6 @@
   return "";
 }
 
-static std::string PrintMode(int mode) {
-  if (mode == TINYGLTF_MODE_POINTS) {
-    return "POINTS";
-  } else if (mode == TINYGLTF_MODE_LINE) {
-    return "LINE";
-  } else if (mode == TINYGLTF_MODE_LINE_LOOP) {
-    return "LINE_LOOP";
-  } else if (mode == TINYGLTF_MODE_TRIANGLES) {
-    return "TRIANGLES";
-  } else if (mode == TINYGLTF_MODE_TRIANGLE_FAN) {
-    return "TRIANGLE_FAN";
-  } else if (mode == TINYGLTF_MODE_TRIANGLE_STRIP) {
-    return "TRIANGLE_STRIP";
-  }
-  return "**UNKNOWN**";
-}
-
-static std::string PrintTarget(int target) {
-  if (target == 34962) {
-    return "GL_ARRAY_BUFFER";
-  } else if (target == 34963) {
-    return "GL_ELEMENT_ARRAY_BUFFER";
-  } else {
-    return "**UNKNOWN**";
-  }
-}
-
-static std::string PrintType(int ty) {
-  if (ty == TINYGLTF_TYPE_SCALAR) {
-    return "SCALAR";
-  } else if (ty == TINYGLTF_TYPE_VECTOR) {
-    return "VECTOR";
-  } else if (ty == TINYGLTF_TYPE_VEC2) {
-    return "VEC2";
-  } else if (ty == TINYGLTF_TYPE_VEC3) {
-    return "VEC3";
-  } else if (ty == TINYGLTF_TYPE_VEC4) {
-    return "VEC4";
-  } else if (ty == TINYGLTF_TYPE_MATRIX) {
-    return "MATRIX";
-  } else if (ty == TINYGLTF_TYPE_MAT2) {
-    return "MAT2";
-  } else if (ty == TINYGLTF_TYPE_MAT3) {
-    return "MAT3";
-  } else if (ty == TINYGLTF_TYPE_MAT4) {
-    return "MAT4";
-  }
-  return "**UNKNOWN**";
-}
-
-static std::string PrintComponentType(int ty) {
-  if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) {
-    return "BYTE";
-  } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
-    return "UNSIGNED_BYTE";
-  } else if (ty == TINYGLTF_COMPONENT_TYPE_SHORT) {
-    return "SHORT";
-  } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
-    return "UNSIGNED_SHORT";
-  } else if (ty == TINYGLTF_COMPONENT_TYPE_INT) {
-    return "INT";
-  } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
-    return "UNSIGNED_INT";
-  } else if (ty == TINYGLTF_COMPONENT_TYPE_FLOAT) {
-    return "FLOAT";
-  } else if (ty == TINYGLTF_COMPONENT_TYPE_DOUBLE) {
-    return "DOUBLE";
-  }
-
-  return "**UNKNOWN**";
-}
-
-#if 0
-static std::string PrintParameterType(int ty) {
-  if (ty == TINYGLTF_PARAMETER_TYPE_BYTE) {
-    return "BYTE";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE) {
-    return "UNSIGNED_BYTE";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_SHORT) {
-    return "SHORT";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT) {
-    return "UNSIGNED_SHORT";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_INT) {
-    return "INT";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT) {
-    return "UNSIGNED_INT";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_FLOAT) {
-    return "FLOAT";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_FLOAT_VEC2) {
-    return "FLOAT_VEC2";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_FLOAT_VEC3) {
-    return "FLOAT_VEC3";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_FLOAT_VEC4) {
-    return "FLOAT_VEC4";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_INT_VEC2) {
-    return "INT_VEC2";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_INT_VEC3) {
-    return "INT_VEC3";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_INT_VEC4) {
-    return "INT_VEC4";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_BOOL) {
-    return "BOOL";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_BOOL_VEC2) {
-    return "BOOL_VEC2";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_BOOL_VEC3) {
-    return "BOOL_VEC3";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_BOOL_VEC4) {
-    return "BOOL_VEC4";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_FLOAT_MAT2) {
-    return "FLOAT_MAT2";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_FLOAT_MAT3) {
-    return "FLOAT_MAT3";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_FLOAT_MAT4) {
-    return "FLOAT_MAT4";
-  } else if (ty == TINYGLTF_PARAMETER_TYPE_SAMPLER_2D) {
-    return "SAMPLER_2D";
-  }
-
-  return "**UNKNOWN**";
-}
-#endif
-
-static std::string PrintWrapMode(int mode) {
-  if (mode == TINYGLTF_TEXTURE_WRAP_REPEAT) {
-    return "REPEAT";
-  } else if (mode == TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE) {
-    return "CLAMP_TO_EDGE";
-  } else if (mode == TINYGLTF_TEXTURE_WRAP_MIRRORED_REPEAT) {
-    return "MIRRORED_REPEAT";
-  }
-
-  return "**UNKNOWN**";
-}
-
-static std::string PrintFilterMode(int mode) {
-  if (mode == TINYGLTF_TEXTURE_FILTER_NEAREST) {
-    return "NEAREST";
-  } else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR) {
-    return "LINEAR";
-  } else if (mode == TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST) {
-    return "NEAREST_MIPMAP_NEAREST";
-  } else if (mode == TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR) {
-    return "NEAREST_MIPMAP_LINEAR";
-  } else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST) {
-    return "LINEAR_MIPMAP_NEAREST";
-  } else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR) {
-    return "LINEAR_MIPMAP_LINEAR";
-  }
-  return "**UNKNOWN**";
-}
-
-static std::string PrintIntArray(const std::vector<int> &arr) {
-  if (arr.size() == 0) {
-    return "";
-  }
-
-  std::stringstream ss;
-  ss << "[ ";
-  for (size_t i = 0; i < arr.size(); i++) {
-    ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
-  }
-  ss << " ]";
-
-  return ss.str();
-}
-
-static std::string PrintFloatArray(const std::vector<double> &arr) {
-  if (arr.size() == 0) {
-    return "";
-  }
-
-  std::stringstream ss;
-  ss << "[ ";
-  for (size_t i = 0; i < arr.size(); i++) {
-    ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
-  }
-  ss << " ]";
-
-  return ss.str();
-}
-
 static std::string Indent(const int indent) {
   std::string s;
   for (int i = 0; i < indent; i++) {
@@ -206,168 +28,7 @@
   return s;
 }
 
-static std::string PrintParameterValue(const tinygltf::Parameter &param) {
-  if (!param.number_array.empty()) {
-    return PrintFloatArray(param.number_array);
-  } else {
-    return param.string_value;
-  }
-}
 
-#if 0
-static std::string PrintParameterMap(const tinygltf::ParameterMap &pmap) {
-  std::stringstream ss;
-
-  ss << pmap.size() << std::endl;
-  for (auto &kv : pmap) {
-    ss << kv.first << " : " << PrintParameterValue(kv.second) << std::endl;
-  }
-
-  return ss.str();
-}
-#endif
-
-static std::string PrintValue(const std::string &name,
-                              const tinygltf::Value &value, const int indent, const bool tag = true) {
-  std::stringstream ss;
-
-  if (value.IsObject()) {
-    const tinygltf::Value::Object &o = value.Get<tinygltf::Value::Object>();
-    tinygltf::Value::Object::const_iterator it(o.begin());
-    tinygltf::Value::Object::const_iterator itEnd(o.end());
-    for (; it != itEnd; it++) {
-      ss << PrintValue(it->first, it->second, indent + 1) << std::endl;
-    }
-  } else if (value.IsString()) {
-    if (tag) {
-      ss << Indent(indent) << name << " : " << value.Get<std::string>();
-    } else {
-      ss << " " << value.Get<std::string>() << " ";
-    }
-  } else if (value.IsBool()) {
-    if (tag) {
-      ss << Indent(indent) << name << " : " << value.Get<bool>();
-    } else {
-      ss << " " << value.Get<bool>() << " ";
-    }
-  } else if (value.IsNumber()) {
-    if (tag) {
-      ss << Indent(indent) << name << " : " << value.Get<double>();
-    } else {
-      ss << " " << value.Get<double>() << " ";
-    }
-  } else if (value.IsInt()) {
-    if (tag) {
-      ss << Indent(indent) << name << " : " << value.Get<int>();
-    } else {
-      ss << " " << value.Get<int>() << " ";
-    }
-  } else if (value.IsArray()) {
-    ss << Indent(indent) << name << " [ ";
-    for (size_t i = 0; i < value.Size(); i++) {
-      ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */false);
-      if (i != (value.ArrayLen()-1)) {
-        ss << ", ";
-      }
-
-    }
-    ss << Indent(indent) << "] ";
-  }
-
-  // @todo { binary }
-
-  return ss.str();
-}
-
-static void DumpNode(const tinygltf::Node &node, int indent) {
-  std::cout << Indent(indent) << "name        : " << node.name << std::endl;
-  std::cout << Indent(indent) << "camera      : " << node.camera << std::endl;
-  std::cout << Indent(indent) << "mesh        : " << node.mesh << std::endl;
-  if (!node.rotation.empty()) {
-    std::cout << Indent(indent)
-              << "rotation    : " << PrintFloatArray(node.rotation)
-              << std::endl;
-  }
-  if (!node.scale.empty()) {
-    std::cout << Indent(indent)
-              << "scale       : " << PrintFloatArray(node.scale) << std::endl;
-  }
-  if (!node.translation.empty()) {
-    std::cout << Indent(indent)
-              << "translation : " << PrintFloatArray(node.translation)
-              << std::endl;
-  }
-
-  if (!node.matrix.empty()) {
-    std::cout << Indent(indent)
-              << "matrix      : " << PrintFloatArray(node.matrix) << std::endl;
-  }
-
-  std::cout << Indent(indent)
-            << "children    : " << PrintIntArray(node.children) << std::endl;
-}
-
-static void DumpStringIntMap(const std::map<std::string, int> &m, int indent) {
-  std::map<std::string, int>::const_iterator it(m.begin());
-  std::map<std::string, int>::const_iterator itEnd(m.end());
-  for (; it != itEnd; it++) {
-    std::cout << Indent(indent) << it->first << ": " << it->second << std::endl;
-  }
-}
-
-static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
-  std::cout << Indent(indent) << "material : " << primitive.material
-            << std::endl;
-  std::cout << Indent(indent) << "indices : " << primitive.indices << std::endl;
-  std::cout << Indent(indent) << "mode     : " << PrintMode(primitive.mode)
-            << "(" << primitive.mode << ")" << std::endl;
-  std::cout << Indent(indent)
-            << "attributes(items=" << primitive.attributes.size() << ")"
-            << std::endl;
-  DumpStringIntMap(primitive.attributes, indent + 1);
-
-  std::cout << Indent(indent) << "extras :" << std::endl
-            << PrintValue("extras", primitive.extras, indent + 1) << std::endl;
-}
-
-static void DumpExtensions(const tinygltf::ExtensionMap &extension, const int indent)
-{
-  // TODO(syoyo): pritty print Value
-  for (auto &e : extension) {
-    std::cout << Indent(indent) << e.first << std::endl;
-    std::cout << PrintValue("extensions", e.second, indent+1) << std::endl;
-  }  
-}
-
-static float DecodeScalarAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model)
-{
-  const tinygltf::BufferView &bufferView = model.bufferViews[accessor.bufferView];
-  const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
-
-  const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
-  if (addr == nullptr) {
-    std::cerr << "Invalid glTF data?" << std::endl;
-    return 0.0f;
-  }
-
-  float value = 0.0f;
-
-  if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_BYTE) {
-    value = tinygltf::DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr)));
-  } else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
-    value = tinygltf::DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr)));
-  } else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_SHORT) {
-    value = tinygltf::DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr)));
-  } else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
-    value = tinygltf::DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr)));
-  } else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) {
-    value = *(reinterpret_cast<const float*>(addr));
-  } else {
-    std::cerr << "??? Unknown componentType : " << PrintComponentType(accessor.componentType) << std::endl;
-  }
-
-  return value;
-}
 
 static void ProcessAnimation(const tinygltf::Animation &animation, const tinygltf::Model &model)
 {
@@ -401,8 +62,10 @@
 
     for (size_t i = 0; i < accessor.count; i++) {
       if (accessor.type == TINYGLTF_TYPE_SCALAR) {
-        float v = DecodeScalarAnimationValue(i, accessor, model);
-        std::cout << Indent(2) << "input value[" << i << "] = " << v << std::endl;
+        float v;
+        if (tinygltf::util::DecodeScalarAnimationValue(i, accessor, model, &v)) {
+          std::cout << Indent(2) << "input value[" << i << "] = " << v << std::endl;
+        }
       }
     }
 
diff --git a/tiny_gltf.h b/tiny_gltf.h
index 8608501..21bf527 100644
--- a/tiny_gltf.h
+++ b/tiny_gltf.h
@@ -196,20 +196,6 @@
   }
 }
 
-// Utility function for decoding animation value
-static inline float DecodeAnimationChannelValue(int8_t c) {
-  return std::max(float(c) / 127.0f, -1.0f);
-}
-static inline float DecodeAnimationChannelValue(uint8_t c) {
-  return float(c) / 255.0f;
-}
-static inline float DecodeAnimationChannelValue(int16_t c) {
-  return std::max(float(c) / 32767.0f, -1.0f);
-}
-static inline float DecodeAnimationChannelValue(uint16_t c) {
-  return float(c) / 65525.0f;
-}
-
 bool IsDataURI(const std::string &in);
 bool DecodeDataURI(std::vector<unsigned char> *out, std::string &mime_type,
                    const std::string &in, size_t reqBytes, bool checkSize);
@@ -2036,7 +2022,7 @@
 
 const uint8_t *GetBufferAddress(const int i, const Accessor &accessor, const BufferView &bufferViewObject, const Buffer &buffer) {
 
-  if (i >= accessor.count) return nullptr;
+  if (i >= int(accessor.count)) return nullptr;
 
   int byte_stride = accessor.ByteStride(bufferViewObject);
   if (byte_stride == -1) {
@@ -3529,7 +3515,7 @@
     {
       if (primitive.indices > -1) // has indices from parsing step, must be Element Array Buffer
       {
-        model->bufferViews[model->accessors[primitive.indices].bufferView]
+        model->bufferViews[size_t(model->accessors[size_t(primitive.indices)].bufferView)]
             .target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
         // we could optionally check if acessors' bufferView type is Scalar, as it should be
       }
@@ -4616,23 +4602,23 @@
   const int padding_size = content.size() % 4;
 
   // 12 bytes for header, JSON content length, 8 bytes for JSON chunk info, padding
-  const int length = 12 + 8 + content.size() + padding_size;
+  const int length = 12 + 8 + int(content.size()) + padding_size;
   
-  gltfFile.write(header.c_str(), header.size());
+  gltfFile.write(header.c_str(), std::streamsize(header.size()));
   gltfFile.write(reinterpret_cast<const char *>(&version), sizeof(version));
   gltfFile.write(reinterpret_cast<const char *>(&length), sizeof(length));
 
   // JSON chunk info, then JSON data
-  const int model_length = content.size() + padding_size;
+  const int model_length = int(content.size()) + padding_size;
   const int model_format = 0x4E4F534A;
   gltfFile.write(reinterpret_cast<const char *>(&model_length), sizeof(model_length));
   gltfFile.write(reinterpret_cast<const char *>(&model_format), sizeof(model_format));
-  gltfFile.write(content.c_str(), content.size());
+  gltfFile.write(content.c_str(), std::streamsize(content.size()));
 
   // Chunk must be multiplies of 4, so pad with spaces
   if (padding_size > 0) {
-    const std::string padding = std::string(padding_size, ' ');
-    gltfFile.write(padding.c_str(), padding.size());
+    const std::string padding = std::string(size_t(padding_size), ' ');
+    gltfFile.write(padding.c_str(), std::streamsize(padding.size()));
   }
 }
 
diff --git a/tiny_gltf_util.h b/tiny_gltf_util.h
new file mode 100644
index 0000000..64fc6ca
--- /dev/null
+++ b/tiny_gltf_util.h
@@ -0,0 +1,294 @@
+//
+// TinyGLTF utility functions
+//
+//
+// The MIT License (MIT)
+//
+// Copyright (c) 2015 - 2018 Syoyo Fujita, Aurélien Chatelain and many
+// contributors.
+//
+
+#include <iostream>
+
+#include "tiny_gltf.h"
+
+namespace tinygltf {
+
+namespace util {
+
+static std::string PrintMode(int mode) {
+  if (mode == TINYGLTF_MODE_POINTS) {
+    return "POINTS";
+  } else if (mode == TINYGLTF_MODE_LINE) {
+    return "LINE";
+  } else if (mode == TINYGLTF_MODE_LINE_LOOP) {
+    return "LINE_LOOP";
+  } else if (mode == TINYGLTF_MODE_TRIANGLES) {
+    return "TRIANGLES";
+  } else if (mode == TINYGLTF_MODE_TRIANGLE_FAN) {
+    return "TRIANGLE_FAN";
+  } else if (mode == TINYGLTF_MODE_TRIANGLE_STRIP) {
+    return "TRIANGLE_STRIP";
+  }
+  return "**UNKNOWN**";
+}
+
+static std::string PrintTarget(int target) {
+  if (target == 34962) {
+    return "GL_ARRAY_BUFFER";
+  } else if (target == 34963) {
+    return "GL_ELEMENT_ARRAY_BUFFER";
+  } else {
+    return "**UNKNOWN**";
+  }
+}
+
+static std::string PrintType(int ty) {
+  if (ty == TINYGLTF_TYPE_SCALAR) {
+    return "SCALAR";
+  } else if (ty == TINYGLTF_TYPE_VECTOR) {
+    return "VECTOR";
+  } else if (ty == TINYGLTF_TYPE_VEC2) {
+    return "VEC2";
+  } else if (ty == TINYGLTF_TYPE_VEC3) {
+    return "VEC3";
+  } else if (ty == TINYGLTF_TYPE_VEC4) {
+    return "VEC4";
+  } else if (ty == TINYGLTF_TYPE_MATRIX) {
+    return "MATRIX";
+  } else if (ty == TINYGLTF_TYPE_MAT2) {
+    return "MAT2";
+  } else if (ty == TINYGLTF_TYPE_MAT3) {
+    return "MAT3";
+  } else if (ty == TINYGLTF_TYPE_MAT4) {
+    return "MAT4";
+  }
+  return "**UNKNOWN**";
+}
+
+static std::string PrintComponentType(int ty) {
+  if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) {
+    return "BYTE";
+  } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
+    return "UNSIGNED_BYTE";
+  } else if (ty == TINYGLTF_COMPONENT_TYPE_SHORT) {
+    return "SHORT";
+  } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
+    return "UNSIGNED_SHORT";
+  } else if (ty == TINYGLTF_COMPONENT_TYPE_INT) {
+    return "INT";
+  } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
+    return "UNSIGNED_INT";
+  } else if (ty == TINYGLTF_COMPONENT_TYPE_FLOAT) {
+    return "FLOAT";
+  } else if (ty == TINYGLTF_COMPONENT_TYPE_DOUBLE) {
+    return "DOUBLE";
+  }
+
+  return "**UNKNOWN**";
+}
+
+static std::string PrintWrapMode(int mode) {
+  if (mode == TINYGLTF_TEXTURE_WRAP_REPEAT) {
+    return "REPEAT";
+  } else if (mode == TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE) {
+    return "CLAMP_TO_EDGE";
+  } else if (mode == TINYGLTF_TEXTURE_WRAP_MIRRORED_REPEAT) {
+    return "MIRRORED_REPEAT";
+  }
+
+  return "**UNKNOWN**";
+}
+
+static std::string PrintFilterMode(int mode) {
+  if (mode == TINYGLTF_TEXTURE_FILTER_NEAREST) {
+    return "NEAREST";
+  } else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR) {
+    return "LINEAR";
+  } else if (mode == TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST) {
+    return "NEAREST_MIPMAP_NEAREST";
+  } else if (mode == TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR) {
+    return "NEAREST_MIPMAP_LINEAR";
+  } else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST) {
+    return "LINEAR_MIPMAP_NEAREST";
+  } else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR) {
+    return "LINEAR_MIPMAP_LINEAR";
+  }
+  return "**UNKNOWN**";
+}
+
+static int GetAnimationSamplerInputCount(const tinygltf::AnimationSampler &sampler, const tinygltf::Model &model)
+{
+  const tinygltf::Accessor &accessor = model.accessors[sampler.input];
+  return accessor.count;
+}
+
+static int GetAnimationSamplerOutputCount(const tinygltf::AnimationSampler &sampler, const tinygltf::Model &model)
+{
+  const tinygltf::Accessor &accessor = model.accessors[sampler.output];
+  return accessor.count;
+}
+
+static bool GetAnimationSamplerInputMinMax(const tinygltf::AnimationSampler &sampler, const tinygltf::Model &model, float *min_value, float *max_value)
+{
+  const tinygltf::Accessor &accessor = model.accessors[sampler.input];
+
+  // Assume scalar value.
+  if ((accessor.minValues.size() > 0) &&
+      (accessor.maxValues.size() > 0)) {
+    (*min_value) = accessor.minValues[0];
+    (*max_value) = accessor.maxValues[0];
+    return true;
+  } else {
+    (*min_value) = 0.0f;
+    (*max_value) = 0.0f;
+    return false;
+  }
+}
+
+// Utility function for decoding animation value
+static inline float DecodeAnimationChannelValue(int8_t c) {
+  return std::max(float(c) / 127.0f, -1.0f);
+}
+static inline float DecodeAnimationChannelValue(uint8_t c) {
+  return float(c) / 255.0f;
+}
+static inline float DecodeAnimationChannelValue(int16_t c) {
+  return std::max(float(c) / 32767.0f, -1.0f);
+}
+static inline float DecodeAnimationChannelValue(uint16_t c) {
+  return float(c) / 65525.0f;
+}
+
+static bool DecodeScalarAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model, float *scalar)
+{
+  const BufferView &bufferView = model.bufferViews[accessor.bufferView];
+  const Buffer &buffer = model.buffers[bufferView.buffer];
+
+  const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
+  if (addr == nullptr) {
+    std::cerr << "Invalid glTF data?" << std::endl;
+    return false;
+  }
+
+  float value = 0.0f;
+
+  if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_BYTE) {
+    value = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr)));
+  } else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
+    value = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr)));
+  } else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_SHORT) {
+    value = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr)));
+  } else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
+    value = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr)));
+  } else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) {
+    value = *(reinterpret_cast<const float*>(addr));
+  } else {
+    std::cerr << "??? Unknown componentType : " << PrintComponentType(accessor.componentType) << std::endl;
+    return false;
+  }
+
+  (*scalar) = value;
+
+  return true;
+}
+
+static bool DecodeTranslationAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model, float *xyz)
+{
+  if (accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
+    std::cerr << "`translation` must be float type." << std::endl;
+    return false;
+  }
+
+  const BufferView &bufferView = model.bufferViews[accessor.bufferView];
+  const Buffer &buffer = model.buffers[bufferView.buffer];
+
+  const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
+  if (addr == nullptr) {
+    std::cerr << "Invalid glTF data?" << std::endl;
+    return 0.0f;
+  }
+
+  const float *ptr = reinterpret_cast<const float*>(addr);
+
+  xyz[0] = *(ptr + 0);
+  xyz[1] = *(ptr + 1);
+  xyz[2] = *(ptr + 2);
+
+  return true;
+}
+
+static bool DecodeScaleAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model, float *xyz)
+{
+  if (accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
+    std::cerr << "`scale` must be float type." << std::endl;
+    return false;
+  }
+
+  const BufferView &bufferView = model.bufferViews[accessor.bufferView];
+  const Buffer &buffer = model.buffers[bufferView.buffer];
+
+  const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
+  if (addr == nullptr) {
+    std::cerr << "Invalid glTF data?" << std::endl;
+    return 0.0f;
+  }
+
+  const float *ptr = reinterpret_cast<const float*>(addr);
+
+  xyz[0] = *(ptr + 0);
+  xyz[1] = *(ptr + 1);
+  xyz[2] = *(ptr + 2);
+
+  return true;
+}
+
+static bool DecodeRotationAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model, float *xyzw)
+{
+  const BufferView &bufferView = model.bufferViews[accessor.bufferView];
+  const Buffer &buffer = model.buffers[bufferView.buffer];
+
+  const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
+  if (addr == nullptr) {
+    std::cerr << "Invalid glTF data?" << std::endl;
+    return false;
+  }
+
+  float value = 0.0f;
+
+  if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_BYTE) {
+    xyzw[0] = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr) + 0));
+    xyzw[1] = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr) + 1));
+    xyzw[2] = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr) + 2));
+    xyzw[3] = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr) + 3));
+  } else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
+    xyzw[0] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr) + 0));
+    xyzw[1] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr) + 1));
+    xyzw[2] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr) + 2));
+    xyzw[3] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr) + 3));
+  } else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_SHORT) {
+    xyzw[0] = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr) + 0));
+    xyzw[1] = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr) + 1));
+    xyzw[2] = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr) + 2));
+    xyzw[3] = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr) + 3));
+  } else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
+    xyzw[0] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr) + 0));
+    xyzw[1] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr) + 1));
+    xyzw[2] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr) + 2));
+    xyzw[3] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr) + 3));
+  } else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) {
+    xyzw[0] = *(reinterpret_cast<const float*>(addr) + 0);
+    xyzw[1] = *(reinterpret_cast<const float*>(addr) + 1);
+    xyzw[2] = *(reinterpret_cast<const float*>(addr) + 2);
+    xyzw[3] = *(reinterpret_cast<const float*>(addr) + 3);
+  } else {
+    std::cerr << "??? Unknown componentType : " << PrintComponentType(accessor.componentType) << std::endl;
+    return false;
+  }
+
+  return true;
+}
+
+} // namespace util
+
+} // namespace tinygltf