X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-scene3d%2Fpublic-api%2Floader%2Fmesh-definition.cpp;h=18093a5161ded583245f42997a75e2db463e23b2;hb=963c6afad45fd6a64d6e3cd5063796eaa7d3c41a;hp=10adc2d98d045a6fd5c0f41486bae9a404788ea3;hpb=554ceadad196d0607459efb54f0ce312240d4b44;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-scene3d/public-api/loader/mesh-definition.cpp b/dali-scene3d/public-api/loader/mesh-definition.cpp index 10adc2d..18093a5 100644 --- a/dali-scene3d/public-api/loader/mesh-definition.cpp +++ b/dali-scene3d/public-api/loader/mesh-definition.cpp @@ -20,10 +20,12 @@ // EXTERNAL INCLUDES #include +#include #include +#include #include #include -#include "dali/devel-api/adaptor-framework/pixel-buffer.h" +#include namespace Dali { @@ -33,39 +35,42 @@ namespace Loader { namespace { +template class IndexProvider { public: + using IndexType = typename std::conditional_t; IndexProvider(const uint16_t* indices) : mData(reinterpret_cast(indices)), mFunc(indices ? IncrementPointer : Increment) { } - uint16_t operator()() + IndexType operator()() { return mFunc(mData); } private: - static uint16_t Increment(uintptr_t& data) + static IndexType Increment(uintptr_t& data) { - return static_cast(data++); + // mData was 'zero' at construct time. Just simply return counter start with 0. + return static_cast(data++); } - static uint16_t IncrementPointer(uintptr_t& data) + static IndexType IncrementPointer(uintptr_t& data) { - auto iPtr = reinterpret_cast(data); + auto iPtr = reinterpret_cast(data); auto result = *iPtr; data = reinterpret_cast(++iPtr); return result; } uintptr_t mData; - uint16_t (*mFunc)(uintptr_t&); + IndexType (*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 +84,7 @@ bool ReadBlob(const MeshDefinition::Blob& descriptor, std::istream& source, uint if(descriptor.IsConsecutive()) { - return !!source.read(reinterpret_cast(target), descriptor.mLength); + return !!source.read(reinterpret_cast(target), static_cast(static_cast(descriptor.mLength))); } else { @@ -210,13 +215,23 @@ void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Acces raw.mAttribs.push_back({"aJoints", Property::VECTOR4, static_cast(outBufferSize / sizeof(Vector4)), std::move(buffer)}); } -void GenerateNormals(MeshDefinition::RawData& raw) +template> +bool GenerateNormals(MeshDefinition::RawData& raw) { + using IndexType = typename IndexProviderType::IndexType; + + // mIndicies size must be even if we use 32bit indices. + if(DALI_UNLIKELY(use32BitsIndices && !raw.mIndices.empty() && !(raw.mIndices.size() % (sizeof(IndexType) / sizeof(uint16_t)) == 0))) + { + return false; + } + auto& attribs = raw.mAttribs; DALI_ASSERT_DEBUG(attribs.size() > 0); // positions - IndexProvider getIndex(raw.mIndices.data()); - const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : static_cast(raw.mIndices.size()); + IndexProviderType getIndex(raw.mIndices.data()); + + const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : static_cast(raw.mIndices.size() / (sizeof(IndexType) / sizeof(uint16_t))); auto* positions = reinterpret_cast(attribs[0].mData.data()); @@ -225,8 +240,8 @@ void GenerateNormals(MeshDefinition::RawData& raw) 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]]}; + IndexType indices[]{getIndex(), getIndex(), getIndex()}; + Vector3 pos[]{positions[indices[0]], positions[indices[1]], positions[indices[2]]}; Vector3 a = pos[1] - pos[0]; Vector3 b = pos[2] - pos[0]; @@ -245,85 +260,103 @@ void GenerateNormals(MeshDefinition::RawData& raw) } attribs.push_back({"aNormal", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer)}); + + return true; } -void GenerateTangentsWithUvs(MeshDefinition::RawData& raw) +template, typename = std::enable_if_t<(std::is_same::value || std::is_same::value)>, typename IndexProviderType = IndexProvider> +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(raw.mIndices.size()); + using IndexType = typename IndexProviderType::IndexType; - auto* positions = reinterpret_cast(attribs[0].mData.data()); - auto* uvs = reinterpret_cast(attribs[2].mData.data()); - - std::vector buffer(attribs[0].mNumElements * sizeof(Vector3)); - auto tangents = reinterpret_cast(buffer.data()); + // mIndicies size must be even if we use 32bit indices. + if(DALI_UNLIKELY(use32BitsIndices && !raw.mIndices.empty() && !(raw.mIndices.size() % (sizeof(IndexType) / sizeof(uint16_t)) == 0))) + { + return false; + } - for(uint32_t i = 0; i < numIndices; i += 3) + auto& attribs = raw.mAttribs; + // Required positions, normals, uvs (if we have). If not, skip generation + if(DALI_UNLIKELY(attribs.size() < (2 + static_cast(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]]}; + return false; + } - float x0 = pos[1].x - pos[0].x; - float y0 = pos[1].y - pos[0].y; - float z0 = pos[1].z - pos[0].z; + std::vector buffer(attribs[0].mNumElements * sizeof(T)); + auto tangents = reinterpret_cast(buffer.data()); - float x1 = pos[2].x - pos[0].x; - float y1 = pos[2].y - pos[0].y; - float z1 = pos[2].z - pos[0].z; + if constexpr(hasUvs) + { + IndexProviderType getIndex(raw.mIndices.data()); - float s0 = uv[1].x - uv[0].x; - float t0 = uv[1].y - uv[0].y; + const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : static_cast(raw.mIndices.size() / (sizeof(IndexType) / sizeof(uint16_t))); - float s1 = uv[2].x - uv[0].x; - float t1 = uv[2].y - uv[0].y; + auto* positions = reinterpret_cast(attribs[0].mData.data()); + auto* uvs = reinterpret_cast(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) + { + IndexType 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(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(attribs[1].mData.data()); - - std::vector buffer(attribs[0].mNumElements * sizeof(Vector3)); - auto tangents = reinterpret_cast(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 +574,9 @@ void MeshDefinition::Blob::ApplyMinMax(const std::vector& 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(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([](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(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([](const float* min, const float* max, uint32_t i, float& value) { value = std::min(std::max(min[i], value), max[i]); })); if(!clampFn) { @@ -664,18 +694,6 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& { ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'."; } - - auto u16s = raw.mIndices.data(); - auto u32s = reinterpret_cast(raw.mIndices.data()); - auto end = u32s + indexCount; - while(u32s != end) - { - *u16s = static_cast(*u32s); - ++u16s; - ++u32s; - } - - raw.mIndices.resize(indexCount); } else if(MaskMatch(mFlags, U8_INDICES)) { @@ -683,10 +701,10 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& mIndices.mBlob.mStride >= sizeof(uint8_t)) && "Index buffer length not a multiple of element size"); const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint8_t); - raw.mIndices.resize(indexCount); // NOTE: we need space for uint32_ts initially. + raw.mIndices.resize(indexCount); // NOTE: we need space for uint16_ts initially. std::string path; - auto u8s = reinterpret_cast(raw.mIndices.data()) + indexCount; + auto u8s = reinterpret_cast(raw.mIndices.data()) + indexCount; auto& stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path); if(!ReadAccessor(mIndices, stream, u8s)) { @@ -709,7 +727,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(raw.mIndices.data()))) @@ -778,8 +795,20 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& else if(mNormals.mBlob.mLength != 0 && isTriangles) { DALI_ASSERT_DEBUG(mNormals.mBlob.mLength == mPositions.mBlob.GetBufferSize()); - GenerateNormals(raw); - hasNormals = true; + static const std::function GenerateNormalsFunction[2] = + { + GenerateNormals, + GenerateNormals, + }; + const bool generateSuccessed = GenerateNormalsFunction[MaskMatch(mFlags, U32_INDICES)](raw); + if(!generateSuccessed) + { + DALI_LOG_ERROR("Failed to generate normal\n"); + } + else + { + hasNormals = true; + } } const auto hasUvs = mTexCoords.IsDefined(); @@ -810,7 +839,7 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& } } - mTexCoords.mBlob.ApplyMinMax(static_cast(bufferSize / sizeof(Vector2)), reinterpret_cast(buffer.data())); + mTexCoords.mBlob.ApplyMinMax(static_cast(uvCount), reinterpret_cast(buffer.data())); raw.mAttribs.push_back({"aTexCoord", Property::VECTOR2, static_cast(uvCount), std::move(buffer)}); } @@ -837,7 +866,33 @@ 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 GenerateTangentsFunction[2][2][2] = + { + { + { + GenerateTangents, + GenerateTangents, + }, + { + GenerateTangents, + GenerateTangents, + }, + }, + { + { + GenerateTangents, + GenerateTangents, + }, + { + GenerateTangents, + GenerateTangents, + }, + }}; + const bool generateSuccessed = GenerateTangentsFunction[MaskMatch(mFlags, U32_INDICES)][mTangentType == Property::VECTOR3][hasUvs](raw); + if(!generateSuccessed) + { + DALI_LOG_ERROR("Failed to generate tangents\n"); + } } if(mColors.IsDefined()) @@ -988,7 +1043,15 @@ MeshGeometry MeshDefinition::Load(RawData&& raw) const { if(!raw.mIndices.empty()) { - meshGeometry.geometry.SetIndexBuffer(raw.mIndices.data(), raw.mIndices.size()); + if(MaskMatch(mFlags, U32_INDICES)) + { + // TODO : We can only store indeces as uint16_type. Send Dali::Geometry that we use it as uint32_t actual. + meshGeometry.geometry.SetIndexBuffer(reinterpret_cast(raw.mIndices.data()), raw.mIndices.size() / 2); + } + else + { + meshGeometry.geometry.SetIndexBuffer(raw.mIndices.data(), raw.mIndices.size()); + } } for(auto& a : raw.mAttribs)