From: Eunki Hong Date: Sat, 18 Feb 2023 10:22:52 +0000 (+0900) Subject: Allow to load uint32_t as indices X-Git-Tag: dali_2.2.16~4^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=963c6afad45fd6a64d6e3cd5063796eaa7d3c41a Allow to load uint32_t as indices Dali's default indices use uint16_t. But if heavy 3D model who need more than 65536 indexes loaded, It will break index. This patch make Scene3D can allow to use uint32_t type indeces load and generete Geometry by it. Change-Id: I6b8096df3fcf855443e6b407342121b9374d9ff8 Signed-off-by: Eunki Hong --- diff --git a/automated-tests/resources/EnvironmentTest.gltf b/automated-tests/resources/EnvironmentTest.gltf index 962e475..b9d85b3 100644 --- a/automated-tests/resources/EnvironmentTest.gltf +++ b/automated-tests/resources/EnvironmentTest.gltf @@ -178,7 +178,6 @@ { "attributes": { "POSITION": 0, - "NORMAL": 1, "TEXCOORD_0": 2 }, "indices": 3, diff --git a/automated-tests/resources/EnvironmentTest_images/roughness_metallic_0.jpg b/automated-tests/resources/EnvironmentTest_images/roughness_metallic_0.jpg new file mode 100644 index 0000000..8ba03d3 Binary files /dev/null and b/automated-tests/resources/EnvironmentTest_images/roughness_metallic_0.jpg differ diff --git a/automated-tests/resources/EnvironmentTest_images/roughness_metallic_1.jpg b/automated-tests/resources/EnvironmentTest_images/roughness_metallic_1.jpg new file mode 100644 index 0000000..d695618 Binary files /dev/null and b/automated-tests/resources/EnvironmentTest_images/roughness_metallic_1.jpg differ diff --git a/dali-scene3d/public-api/loader/mesh-definition.cpp b/dali-scene3d/public-api/loader/mesh-definition.cpp index b23140f..18093a5 100644 --- a/dali-scene3d/public-api/loader/mesh-definition.cpp +++ b/dali-scene3d/public-api/loader/mesh-definition.cpp @@ -35,36 +35,39 @@ 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 char* QUAD("quad"); @@ -212,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()); @@ -227,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]; @@ -247,14 +260,24 @@ void GenerateNormals(MeshDefinition::RawData& raw) } attribs.push_back({"aNormal", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer)}); + + return true; } -template, typename = std::enable_if_t<(std::is_same::value || std::is_same::value)>> +template, typename = std::enable_if_t<(std::is_same::value || std::is_same::value)>, typename IndexProviderType = IndexProvider> bool GenerateTangents(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; // Required positions, normals, uvs (if we have). If not, skip generation - if(attribs.size() < (2 + static_cast(hasUvs))) + if(DALI_UNLIKELY(attribs.size() < (2 + static_cast(hasUvs)))) { return false; } @@ -264,17 +287,18 @@ bool GenerateTangents(MeshDefinition::RawData& raw) if constexpr(hasUvs) { - 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()); auto* uvs = reinterpret_cast(attribs[2].mData.data()); 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]]}; + 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; @@ -670,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)) { @@ -689,7 +701,7 @@ 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; @@ -783,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(); @@ -815,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)}); } @@ -842,18 +866,29 @@ 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()); - static const std::function GenerateTangentsFunction[2][2] = + static const std::function GenerateTangentsFunction[2][2][2] = { { - GenerateTangents, - GenerateTangents, + { + GenerateTangents, + GenerateTangents, + }, + { + GenerateTangents, + GenerateTangents, + }, }, { - GenerateTangents, - GenerateTangents, - }, - }; - const bool generateSuccessed = GenerateTangentsFunction[mTangentType == Property::VECTOR3][hasUvs](raw); + { + 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"); @@ -1008,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)