[dali_2.2.15] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / public-api / loader / mesh-definition.cpp
index 10adc2d..b23140f 100644 (file)
 
 // EXTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/file-stream.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
 #include <dali/integration-api/debug.h>
+#include <dali/public-api/math/compile-time-math.h>
 #include <cstring>
 #include <fstream>
-#include "dali/devel-api/adaptor-framework/pixel-buffer.h"
+#include <type_traits>
 
 namespace Dali
 {
@@ -65,7 +67,7 @@ private:
   uint16_t (*mFunc)(uintptr_t&);
 };
 
-const std::string QUAD("quad");
+const char* QUAD("quad");
 
 ///@brief Reads a blob from the given stream @a source into @a target, which must have
 /// at least @a descriptor.length bytes.
@@ -79,7 +81,7 @@ bool ReadBlob(const MeshDefinition::Blob& descriptor, std::istream& source, uint
 
   if(descriptor.IsConsecutive())
   {
-    return !!source.read(reinterpret_cast<char*>(target), descriptor.mLength);
+    return !!source.read(reinterpret_cast<char*>(target), static_cast<std::streamsize>(static_cast<size_t>(descriptor.mLength)));
   }
   else
   {
@@ -247,83 +249,90 @@ void GenerateNormals(MeshDefinition::RawData& raw)
   attribs.push_back({"aNormal", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer)});
 }
 
-void GenerateTangentsWithUvs(MeshDefinition::RawData& raw)
+template<bool useVec3, bool hasUvs, typename T = std::conditional_t<useVec3, Vector3, Vector4>, typename = std::enable_if_t<(std::is_same<T, Vector3>::value || std::is_same<T, Vector4>::value)>>
+bool GenerateTangents(MeshDefinition::RawData& raw)
 {
   auto& attribs = raw.mAttribs;
-  DALI_ASSERT_DEBUG(attribs.size() > 2); // positions, normals, uvs
-  IndexProvider getIndex(raw.mIndices.data());
-
-  const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : static_cast<uint32_t>(raw.mIndices.size());
-
-  auto* positions = reinterpret_cast<const Vector3*>(attribs[0].mData.data());
-  auto* uvs       = reinterpret_cast<const Vector2*>(attribs[2].mData.data());
-
-  std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(Vector3));
-  auto                 tangents = reinterpret_cast<Vector3*>(buffer.data());
-
-  for(uint32_t i = 0; i < numIndices; i += 3)
+  // Required positions, normals, uvs (if we have). If not, skip generation
+  if(attribs.size() < (2 + static_cast<size_t>(hasUvs)))
   {
-    uint16_t indices[]{getIndex(), getIndex(), getIndex()};
-    Vector3  pos[]{positions[indices[0]], positions[indices[1]], positions[indices[2]]};
-    Vector2  uv[]{uvs[indices[0]], uvs[indices[1]], uvs[indices[2]]};
-
-    float x0 = pos[1].x - pos[0].x;
-    float y0 = pos[1].y - pos[0].y;
-    float z0 = pos[1].z - pos[0].z;
+    return false;
+  }
 
-    float x1 = pos[2].x - pos[0].x;
-    float y1 = pos[2].y - pos[0].y;
-    float z1 = pos[2].z - pos[0].z;
+  std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(T));
+  auto                 tangents = reinterpret_cast<T*>(buffer.data());
 
-    float s0 = uv[1].x - uv[0].x;
-    float t0 = uv[1].y - uv[0].y;
+  if constexpr(hasUvs)
+  {
+    IndexProvider  getIndex(raw.mIndices.data());
+    const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : static_cast<uint32_t>(raw.mIndices.size());
 
-    float s1 = uv[2].x - uv[0].x;
-    float t1 = uv[2].y - uv[0].y;
+    auto* positions = reinterpret_cast<const Vector3*>(attribs[0].mData.data());
+    auto* uvs       = reinterpret_cast<const Vector2*>(attribs[2].mData.data());
 
-    float   r = 1.f / (s0 * t1 - t0 * s1);
-    Vector3 tangent((x0 * t1 - t0 * x1) * r, (y0 * t1 - t0 * y1) * r, (z0 * t1 - t0 * z1) * r);
-    tangents[indices[0]] += tangent;
-    tangents[indices[1]] += tangent;
-    tangents[indices[2]] += tangent;
+    for(uint32_t i = 0; i < numIndices; i += 3)
+    {
+      uint16_t indices[]{getIndex(), getIndex(), getIndex()};
+      Vector3  pos[]{positions[indices[0]], positions[indices[1]], positions[indices[2]]};
+      Vector2  uv[]{uvs[indices[0]], uvs[indices[1]], uvs[indices[2]]};
+
+      float x0 = pos[1].x - pos[0].x;
+      float y0 = pos[1].y - pos[0].y;
+      float z0 = pos[1].z - pos[0].z;
+
+      float x1 = pos[2].x - pos[0].x;
+      float y1 = pos[2].y - pos[0].y;
+      float z1 = pos[2].z - pos[0].z;
+
+      float s0 = uv[1].x - uv[0].x;
+      float t0 = uv[1].y - uv[0].y;
+
+      float s1 = uv[2].x - uv[0].x;
+      float t1 = uv[2].y - uv[0].y;
+
+      float   det = (s0 * t1 - t0 * s1);
+      float   r   = 1.f / ((std::abs(det) < Dali::Epsilon<1000>::value) ? (Dali::Epsilon<1000>::value * (det > 0.0f ? 1.f : -1.f)) : det);
+      Vector3 tangent((x0 * t1 - t0 * x1) * r, (y0 * t1 - t0 * y1) * r, (z0 * t1 - t0 * z1) * r);
+      tangents[indices[0]] += T(tangent);
+      tangents[indices[1]] += T(tangent);
+      tangents[indices[2]] += T(tangent);
+    }
   }
 
   auto* normals = reinterpret_cast<const Vector3*>(attribs[1].mData.data());
   auto  iEnd    = normals + attribs[1].mNumElements;
   while(normals != iEnd)
   {
-    *tangents -= *normals * normals->Dot(*tangents);
-    tangents->Normalize();
-
-    ++tangents;
-    ++normals;
-  }
-  attribs.push_back({"aTangent", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer)});
-}
-
-void GenerateTangents(MeshDefinition::RawData& raw)
-{
-  auto& attribs = raw.mAttribs;
-  DALI_ASSERT_DEBUG(attribs.size() > 1); // positions, normals
-
-  auto* normals = reinterpret_cast<const Vector3*>(attribs[1].mData.data());
-
-  std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(Vector3));
-  auto                 tangents = reinterpret_cast<Vector3*>(buffer.data());
-
-  auto iEnd = normals + attribs[1].mNumElements;
-  while(normals != iEnd)
-  {
-    Vector3 t[]{normals->Cross(Vector3::XAXIS), normals->Cross(Vector3::YAXIS)};
+    Vector3 tangentVec3;
+    if constexpr(hasUvs)
+    {
+      // Calculated by indexs
+      tangentVec3 = Vector3((*tangents).x, (*tangents).y, (*tangents).z);
+    }
+    else
+    {
+      // Only choiced by normal vector. by indexs
+      Vector3 t[]{normals->Cross(Vector3::XAXIS), normals->Cross(Vector3::YAXIS)};
+      tangentVec3 = t[t[1].LengthSquared() > t[0].LengthSquared()];
+    }
 
-    *tangents = t[t[1].LengthSquared() > t[0].LengthSquared()];
-    *tangents -= *normals * normals->Dot(*tangents);
-    tangents->Normalize();
+    tangentVec3 -= *normals * normals->Dot(tangentVec3);
+    tangentVec3.Normalize();
+    if constexpr(useVec3)
+    {
+      *tangents = tangentVec3;
+    }
+    else
+    {
+      *tangents = Vector4(tangentVec3.x, tangentVec3.y, tangentVec3.z, 1.0f);
+    }
 
     ++tangents;
     ++normals;
   }
-  attribs.push_back({"aTangent", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer)});
+  attribs.push_back({"aTangent", useVec3 ? Property::VECTOR3 : Property::VECTOR4, attribs[0].mNumElements, std::move(buffer)});
+
+  return true;
 }
 
 void CalculateTextureSize(uint32_t totalTextureSize, uint32_t& textureWidth, uint32_t& textureHeight)
@@ -541,12 +550,9 @@ void MeshDefinition::Blob::ApplyMinMax(const std::vector<float>& min, const std:
   const auto numComponents = std::max(min.size(), max.size());
 
   using ClampFn   = void (*)(const float*, const float*, uint32_t, float&);
-  ClampFn clampFn = min.empty() ? (max.empty() ? static_cast<ClampFn>(nullptr) : [](const float* min, const float* max, uint32_t i, float& value)
-                                     { value = std::min(max[i], value); })
-                                : (max.empty() ? [](const float* min, const float* max, uint32_t i, float& value)
-                                     { value = std::max(min[i], value); }
-                                               : static_cast<ClampFn>([](const float* min, const float* max, uint32_t i, float& value)
-                                                                      { value = std::min(std::max(min[i], value), max[i]); }));
+  ClampFn clampFn = min.empty() ? (max.empty() ? static_cast<ClampFn>(nullptr) : [](const float* min, const float* max, uint32_t i, float& value) { value = std::min(max[i], value); })
+                                : (max.empty() ? [](const float* min, const float* max, uint32_t i, float& value) { value = std::max(min[i], value); }
+                                               : static_cast<ClampFn>([](const float* min, const float* max, uint32_t i, float& value) { value = std::min(std::max(min[i], value), max[i]); }));
 
   if(!clampFn)
   {
@@ -686,7 +692,7 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
       raw.mIndices.resize(indexCount); // NOTE: we need space for uint32_ts initially.
 
       std::string path;
-      auto u8s = reinterpret_cast<uint8_t*>(raw.mIndices.data()) + indexCount;
+      auto        u8s    = reinterpret_cast<uint8_t*>(raw.mIndices.data()) + indexCount;
       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
       if(!ReadAccessor(mIndices, stream, u8s))
       {
@@ -709,7 +715,6 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
                          "Index buffer length not a multiple of element size");
       raw.mIndices.resize(mIndices.mBlob.mLength / sizeof(unsigned short));
 
-
       std::string path;
       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
       if(!ReadAccessor(mIndices, stream, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
@@ -837,7 +842,22 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
   else if(mTangents.mBlob.mLength != 0 && hasNormals && isTriangles)
   {
     DALI_ASSERT_DEBUG(mTangents.mBlob.mLength == mNormals.mBlob.GetBufferSize());
-    hasUvs ? GenerateTangentsWithUvs(raw) : GenerateTangents(raw);
+    static const std::function<bool(RawData&)> GenerateTangentsFunction[2][2] =
+      {
+        {
+          GenerateTangents<false, false>,
+          GenerateTangents<false, true>,
+        },
+        {
+          GenerateTangents<true, false>,
+          GenerateTangents<true, true>,
+        },
+      };
+    const bool generateSuccessed = GenerateTangentsFunction[mTangentType == Property::VECTOR3][hasUvs](raw);
+    if(!generateSuccessed)
+    {
+      DALI_LOG_ERROR("Failed to generate tangents\n");
+    }
   }
 
   if(mColors.IsDefined())