+MeshDefinition::Accessor::Accessor(const MeshDefinition::Blob& blob,
+ const MeshDefinition::SparseBlob& sparse,
+ Index bufferIndex,
+ bool normalized)
+: mBlob{blob},
+ mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{sparse} : nullptr},
+ mBufferIdx(bufferIndex),
+ mNormalized(normalized)
+{
+}
+
+MeshDefinition::Accessor::Accessor(MeshDefinition::Blob&& blob,
+ MeshDefinition::SparseBlob&& sparse,
+ Index bufferIndex,
+ bool normalized)
+: mBlob{std::move(blob)},
+ mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{std::move(sparse)} : nullptr},
+ mBufferIdx(bufferIndex),
+ mNormalized(normalized)
+{
+}
+
+void MeshDefinition::Blob::ComputeMinMax(std::vector<float>& min, std::vector<float>& max, uint32_t numComponents, uint32_t count, const float* values)
+{
+ min.assign(numComponents, MAXFLOAT);
+ max.assign(numComponents, -MAXFLOAT);
+ for(uint32_t i = 0; i < count; ++i)
+ {
+ for(uint32_t j = 0; j < numComponents; ++j)
+ {
+ min[j] = std::min(min[j], *values);
+ max[j] = std::max(max[j], *values);
+ values++;
+ }
+ }
+}
+
+void MeshDefinition::Blob::ApplyMinMax(const std::vector<float>& min, const std::vector<float>& max, uint32_t count, float* values, std::vector<uint32_t>* sparseIndices)
+{
+ DALI_ASSERT_DEBUG(max.size() == min.size() || max.size() * min.size() == 0);
+ 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]); }));
+
+ if(!clampFn)
+ {
+ return;
+ }
+
+ auto end = values + count * numComponents;
+ while(values != end)
+ {
+ auto nextElement = values + numComponents;
+ uint32_t i = 0;
+ while(values != nextElement)
+ {
+ clampFn(min.data(), max.data(), i, *values);
+ ++values;
+ ++i;
+ }
+ }
+}
+
+MeshDefinition::Blob::Blob(uint32_t offset, uint32_t length, uint16_t stride, uint16_t elementSizeHint, const std::vector<float>& min, const std::vector<float>& max)
+: mOffset(offset),
+ mLength(length),
+ mStride(stride),
+ mElementSizeHint(elementSizeHint),
+ mMin(min),
+ mMax(max)
+{
+}
+
+uint32_t MeshDefinition::Blob::GetBufferSize() const
+{
+ return mLength;
+}
+
+void MeshDefinition::Blob::ComputeMinMax(uint32_t numComponents, uint32_t count, float* values)
+{
+ ComputeMinMax(mMin, mMax, numComponents, count, values);
+}
+
+void MeshDefinition::Blob::ApplyMinMax(uint32_t count, float* values, std::vector<uint32_t>* sparseIndices) const
+{
+ ApplyMinMax(mMin, mMax, count, values, sparseIndices);
+}
+
+void MeshDefinition::RawData::Attrib::AttachBuffer(Geometry& g) const
+{
+ Property::Map attribMap;
+ attribMap[mName] = mType;
+ VertexBuffer attribBuffer = VertexBuffer::New(attribMap);
+ attribBuffer.SetData(mData.data(), mNumElements);
+
+ g.AddVertexBuffer(attribBuffer);
+}
+
+bool MeshDefinition::IsQuad() const
+{
+ return CaseInsensitiveStringCompare(QUAD, mUri);
+}
+
+bool MeshDefinition::IsSkinned() const
+{
+ return !mJoints.empty() && !mWeights.empty();
+}
+
+bool MeshDefinition::HasVertexColor() const
+{
+ return !mColors.empty();
+}
+
+uint32_t MeshDefinition::GetNumberOfJointSets() const
+{
+ uint32_t number = static_cast<uint32_t>(mJoints.size());
+ if(number > MeshDefinition::MAX_NUMBER_OF_JOINT_SETS)
+ {
+ number = MeshDefinition::MAX_NUMBER_OF_JOINT_SETS;
+ }
+ return number;
+}
+
+bool MeshDefinition::HasBlendShapes() const
+{
+ return !mBlendShapes.empty();
+}
+
+void MeshDefinition::RequestNormals()
+{
+ mNormals.mBlob.mLength = mPositions.mBlob.GetBufferSize();
+}
+
+void MeshDefinition::RequestTangents()
+{
+ mTangents.mBlob.mLength = mNormals.mBlob.GetBufferSize();
+}
+
+MeshDefinition::RawData
+MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& buffers)
+{
+ RawData raw;
+ if (IsQuad())
+ {
+ return raw;
+ }
+
+ std::string meshPath;
+ meshPath = modelsPath + mUri;
+
+ std::unique_ptr<Dali::FileStream> daliFileStream(nullptr);
+ std::iostream* fileStream = nullptr;
+ if (!mUri.empty())
+ {
+ daliFileStream.reset(new Dali::FileStream(meshPath, FileStream::READ | FileStream::BINARY));
+ fileStream = &daliFileStream->GetStream();
+ if(!fileStream->good() || !fileStream->rdbuf()->in_avail())
+ {
+ DALI_LOG_ERROR("Fail to open buffer from %s.\n", meshPath.c_str());
+ fileStream = nullptr;
+ }
+ }
+
+ LoadAccessorInputs indicesInput = {raw, mIndices, mFlags, fileStream, meshPath, buffers};
+ LoadIndices(indicesInput);
+
+ LoadAccessorInputs positionsInput = {raw, mPositions, mFlags, fileStream, meshPath, buffers};
+ uint32_t numberOfVertices = LoadPositions(positionsInput, HasBlendShapes());
+
+ const auto isTriangles = mPrimitiveType == Geometry::TRIANGLES;
+ LoadAccessorInputs normalsInput = {raw, mNormals, mFlags, fileStream, meshPath, buffers};
+ auto hasNormals = LoadNormals(normalsInput, isTriangles, mPositions.mBlob.GetBufferSize());
+
+ LoadAccessorListInputs textureCoordinatesInput = {raw, mTexCoords, mFlags, fileStream, meshPath, buffers};
+ LoadTextureCoordinates(textureCoordinatesInput);
+
+ const bool hasUvs = !mTexCoords.empty() && mTexCoords[0].IsDefined();
+ LoadAccessorInputs tangentsInput = {raw, mTangents, mFlags, fileStream, meshPath, buffers};
+ LoadTangents(tangentsInput, hasNormals, hasUvs, isTriangles, mTangentType, mNormals.mBlob.GetBufferSize());
+
+ LoadAccessorListInputs colorsInput = {raw, mColors, mFlags, fileStream, meshPath, buffers};
+ LoadColors(colorsInput);
+
+ if(IsSkinned())
+ {
+ LoadDataType loadDataType = (MaskMatch(mFlags, MeshDefinition::U16_JOINT_IDS)) ? LoadDataType::UNSIGNED_SHORT : (MaskMatch(mFlags, MeshDefinition::U8_JOINT_IDS) ? LoadDataType::UNSIGNED_BYTE : LoadDataType::FLOAT);
+ LoadAccessorListInputs jointsInput = {raw, mJoints, mFlags, fileStream, meshPath, buffers};
+ ReadTypedVectorAccessors<false>(jointsInput, loadDataType, "aJoints");
+
+ loadDataType = (MaskMatch(mFlags, MeshDefinition::U16_WEIGHT)) ? LoadDataType::UNSIGNED_SHORT : (MaskMatch(mFlags, MeshDefinition::U8_WEIGHT) ? LoadDataType::UNSIGNED_BYTE : LoadDataType::FLOAT);
+ LoadAccessorListInputs weightsInput = {raw, mWeights, mFlags, fileStream, meshPath, buffers};
+ ReadTypedVectorAccessors<true>(weightsInput, loadDataType, "aWeights");
+ }
+
+ LoadBlendShapes(raw, mBlendShapes, mBlendShapeHeader, mBlendShapeVersion, numberOfVertices, fileStream, buffers);