2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "dali-scene-loader/public-api/mesh-definition.h"
22 #include "dali/devel-api/adaptor-framework/pixel-buffer.h"
33 using Uint16Vector4 = uint16_t[4];
38 IndexProvider(const uint16_t* indices)
39 : mData(reinterpret_cast<uintptr_t>(indices)),
40 mFunc(indices ? IncrementPointer : Increment)
49 static uint16_t Increment(uintptr_t& data)
51 return static_cast<uint16_t>(data++);
54 static uint16_t IncrementPointer(uintptr_t& data)
56 auto iPtr = reinterpret_cast<const uint16_t*>(data);
58 data = reinterpret_cast<uintptr_t>(++iPtr);
63 uint16_t(*mFunc)(uintptr_t&);
67 const std::string QUAD_STRING("quad");
69 ///@brief Reads a blob from the given stream @a source into @a target, which must have
70 /// at least @a descriptor.length bytes.
71 bool ReadBlob(const MeshDefinition::Blob& descriptor, std::istream& source, uint8_t* target)
73 if (!source.seekg(descriptor.mOffset, std::istream::beg))
78 if (descriptor.IsConsecutive())
80 return !!source.read(reinterpret_cast<char*>(target), descriptor.mLength);
84 DALI_ASSERT_DEBUG(descriptor.mStride > descriptor.mElementSizeHint);
85 const uint32_t diff = descriptor.mStride - descriptor.mElementSizeHint;
86 uint32_t readSize = 0;
87 while (readSize < descriptor.mLength &&
88 source.read(reinterpret_cast<char*>(target), descriptor.mElementSizeHint) &&
89 source.seekg(diff, std::istream::cur))
91 readSize += descriptor.mStride;
92 target += descriptor.mElementSizeHint;
94 return readSize == descriptor.mLength;
99 void ReadValues(const std::vector<uint8_t>& valuesBuffer, const std::vector<uint8_t>& indicesBuffer, uint8_t* target, uint32_t count, uint32_t elementSizeHint)
101 const T* const indicesPtr = reinterpret_cast<const T* const>(indicesBuffer.data());
102 for (uint32_t index = 0u; index < count; ++index)
104 uint32_t valuesIndex = indicesPtr[index] * elementSizeHint;
105 memcpy(target + valuesIndex, &valuesBuffer[index * elementSizeHint], elementSizeHint);
109 bool ReadAccessor(const MeshDefinition::Accessor& accessor, std::istream& source, uint8_t* target)
111 bool success = false;
113 if (accessor.mBlob.IsDefined())
115 success = ReadBlob(accessor.mBlob, source, target);
122 if (accessor.mSparse)
124 const MeshDefinition::Blob& indices = accessor.mSparse->mIndices;
125 const MeshDefinition::Blob& values = accessor.mSparse->mValues;
127 if (!indices.IsDefined() || !values.IsDefined())
132 const auto indicesBufferSize = indices.GetBufferSize();
133 std::vector<uint8_t> indicesBuffer(indicesBufferSize);
134 success = ReadBlob(indices, source, indicesBuffer.data());
140 const auto valuesBufferSize = values.GetBufferSize();
141 std::vector<uint8_t> valuesBuffer(valuesBufferSize);
142 success = ReadBlob(values, source, valuesBuffer.data());
148 switch (indices.mElementSizeHint)
152 ReadValues<uint8_t>(valuesBuffer, indicesBuffer, target, accessor.mSparse->mCount, values.mElementSizeHint);
157 ReadValues<uint16_t>(valuesBuffer, indicesBuffer, target, accessor.mSparse->mCount, values.mElementSizeHint);
162 ReadValues<uint32_t>(valuesBuffer, indicesBuffer, target, accessor.mSparse->mCount, values.mElementSizeHint);
166 DALI_ASSERT_DEBUG(!"Unsupported type for an index");
173 void GenerateNormals(MeshDefinition::RawData& raw)
175 auto& attribs = raw.mAttribs;
176 DALI_ASSERT_DEBUG(attribs.size() > 0); // positions
177 IndexProvider getIndex(raw.mIndices.data());
179 const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : raw.mIndices.size();
181 auto* positions = reinterpret_cast<const Vector3*>(attribs[0].mData.data());
183 std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(Vector3));
184 auto normals = reinterpret_cast<Vector3*>(buffer.data());
186 for (uint32_t i = 0; i < numIndices; i += 3)
188 uint16_t indices[]{ getIndex(), getIndex(), getIndex() };
189 Vector3 pos[]{ positions[indices[0]], positions[indices[1]], positions[indices[2]] };
191 Vector3 a = pos[1] - pos[0];
192 Vector3 b = pos[2] - pos[0];
194 Vector3 normal(a.Cross(b));
195 normals[indices[0]] += normal;
196 normals[indices[1]] += normal;
197 normals[indices[2]] += normal;
200 auto iEnd = normals + attribs[0].mNumElements;
201 while (normals != iEnd)
203 normals->Normalize();
207 attribs.push_back({ "aNormal", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer) });
210 void GenerateTangentsWithUvs(MeshDefinition::RawData& raw)
212 auto& attribs = raw.mAttribs;
213 DALI_ASSERT_DEBUG(attribs.size() > 2); // positions, normals, uvs
214 IndexProvider getIndex(raw.mIndices.data());
216 const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : raw.mIndices.size();
218 auto* positions = reinterpret_cast<const Vector3*>(attribs[0].mData.data());
219 auto* uvs = reinterpret_cast<const Vector2*>(attribs[2].mData.data());
221 std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(Vector3));
222 auto tangents = reinterpret_cast<Vector3*>(buffer.data());
224 for (uint32_t i = 0; i < numIndices; i += 3)
226 uint16_t indices[]{ getIndex(), getIndex(), getIndex() };
227 Vector3 pos[]{ positions[indices[0]], positions[indices[1]], positions[indices[2]] };
228 Vector2 uv[]{ uvs[indices[0]], uvs[indices[1]], uvs[indices[2]] };
230 float x0 = pos[1].x - pos[0].x;
231 float y0 = pos[1].y - pos[0].y;
232 float z0 = pos[1].z - pos[0].z;
234 float x1 = pos[2].x - pos[0].x;
235 float y1 = pos[2].y - pos[0].y;
236 float z1 = pos[2].z - pos[0].z;
238 float s0 = uv[1].x - uv[0].x;
239 float t0 = uv[1].y - uv[0].y;
241 float s1 = uv[2].x - uv[0].x;
242 float t1 = uv[2].y - uv[0].y;
244 float r = 1.f / (s0 * t1 - t0 * s1);
245 Vector3 tangent((x0 * t1 - t0 * x1) * r, (y0 * t1 - t0 * y1) * r, (z0 * t1 - t0 * z1) * r);
246 tangents[indices[0]] += tangent;
247 tangents[indices[1]] += tangent;
248 tangents[indices[2]] += tangent;
251 auto* normals = reinterpret_cast<const Vector3*>(attribs[1].mData.data());
252 auto iEnd = normals + attribs[1].mNumElements;
253 while (normals != iEnd)
255 *tangents -= *normals * normals->Dot(*tangents);
256 tangents->Normalize();
261 attribs.push_back({ "aTangent", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer) });
264 void GenerateTangents(MeshDefinition::RawData& raw)
266 auto& attribs = raw.mAttribs;
267 DALI_ASSERT_DEBUG(attribs.size() > 1); // positions, normals
269 auto* normals = reinterpret_cast<const Vector3*>(attribs[1].mData.data());
271 std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(Vector3));
272 auto tangents = reinterpret_cast<Vector3*>(buffer.data());
274 auto iEnd = normals + attribs[1].mNumElements;
275 while (normals != iEnd)
277 Vector3 t[]{ normals->Cross(Vector3::XAXIS), normals->Cross(Vector3::YAXIS) };
279 *tangents = t[t[1].LengthSquared() > t[0].LengthSquared()];
280 *tangents -= *normals * normals->Dot(*tangents);
281 tangents->Normalize();
286 attribs.push_back({ "aTangent", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer) });
289 void CalculateTextureSize(uint32_t totalTextureSize, uint32_t& textureWidth, uint32_t& textureHeight)
291 DALI_ASSERT_DEBUG(0u != totalTextureSize && "totalTextureSize is zero.")
293 // Calculate the dimensions of the texture.
294 // The total size of the texture is the length of the blend shapes blob.
299 if (0u == totalTextureSize)
305 const uint32_t pow2 = static_cast<uint32_t>(ceil(log2(totalTextureSize)));
306 const uint32_t powWidth = pow2 >> 1u;
307 const uint32_t powHeight = pow2 - powWidth;
309 textureWidth = 1u << powWidth;
310 textureHeight = 1u << powHeight;
313 void CalculateGltf2BlendShapes(uint8_t* geometryBuffer, std::ifstream& binFile, const std::vector<MeshDefinition::BlendShape>& blendShapes, uint32_t numberOfVertices, float& blendShapeUnnormalizeFactor)
315 uint32_t geometryBufferIndex = 0u;
316 float maxDistance = 0.f;
317 Vector3* geometryBufferV3 = reinterpret_cast<Vector3*>(geometryBuffer);
318 for (const auto& blendShape : blendShapes)
320 if (blendShape.deltas.IsDefined())
322 DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % sizeof(Vector3) == 0u) ||
323 blendShape.deltas.mBlob.mStride >= sizeof(Vector3)) &&
324 "Blend Shape position buffer length not a multiple of element size");
326 const auto bufferSize = blendShape.deltas.mBlob.GetBufferSize();
327 std::vector<uint8_t> buffer(bufferSize);
328 if (ReadAccessor(blendShape.deltas, binFile, buffer.data()))
330 blendShape.deltas.mBlob.ApplyMinMax(bufferSize / sizeof(Vector3), reinterpret_cast<float*>(buffer.data()));
331 // Calculate the difference with the original mesh.
332 // Find the max distance to normalize the deltas.
333 const Vector3* const deltasBuffer = reinterpret_cast<const Vector3* const>(buffer.data());
335 for (uint32_t index = 0u; index < numberOfVertices; ++index)
337 Vector3& delta = geometryBufferV3[geometryBufferIndex++];
338 delta = deltasBuffer[index];
340 maxDistance = std::max(maxDistance, delta.LengthSquared());
345 if (blendShape.normals.IsDefined())
347 DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % sizeof(Vector3) == 0u) ||
348 blendShape.normals.mBlob.mStride >= sizeof(Vector3)) &&
349 "Blend Shape normals buffer length not a multiple of element size");
351 const auto bufferSize = blendShape.normals.mBlob.GetBufferSize();
352 std::vector<uint8_t> buffer(bufferSize);
353 if (ReadAccessor(blendShape.normals, binFile, buffer.data()))
355 blendShape.normals.mBlob.ApplyMinMax(bufferSize / sizeof(Vector3), reinterpret_cast<float*>(buffer.data()));
357 // Calculate the difference with the original mesh, and translate to make all values positive.
358 const Vector3* const deltasBuffer = reinterpret_cast<const Vector3* const>(buffer.data());
360 for (uint32_t index = 0u; index < numberOfVertices; ++index)
362 Vector3& delta = geometryBufferV3[geometryBufferIndex++];
363 delta = deltasBuffer[index];
376 if (blendShape.tangents.IsDefined())
378 DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % sizeof(Vector3) == 0u) ||
379 blendShape.tangents.mBlob.mStride >= sizeof(Vector3)) &&
380 "Blend Shape tangents buffer length not a multiple of element size");
382 const auto bufferSize = blendShape.tangents.mBlob.GetBufferSize();
383 std::vector<uint8_t> buffer(bufferSize);
384 if (ReadAccessor(blendShape.tangents, binFile, buffer.data()))
386 blendShape.tangents.mBlob.ApplyMinMax(bufferSize / sizeof(Vector3), reinterpret_cast<float*>(buffer.data()));
388 // Calculate the difference with the original mesh, and translate to make all values positive.
389 const Vector3* const deltasBuffer = reinterpret_cast<const Vector3* const>(buffer.data());
391 for (uint32_t index = 0u; index < numberOfVertices; ++index)
393 Vector3& delta = geometryBufferV3[geometryBufferIndex++];
394 delta = deltasBuffer[index];
408 geometryBufferIndex = 0u;
409 for (const auto& blendShape : blendShapes)
411 // Normalize all the deltas and translate to a possitive value.
412 // Deltas are going to be passed to the shader in a color texture
413 // whose values that are less than zero are clamped.
414 if (blendShape.deltas.IsDefined())
417 const float normalizeFactor = (fabsf(maxDistance) < Math::MACHINE_EPSILON_1000) ? 1.f : (0.5f / sqrtf(maxDistance));
419 for (uint32_t index = 0u; index < numberOfVertices; ++index)
421 Vector3& delta = geometryBufferV3[geometryBufferIndex++];
422 delta.x = Clamp(((delta.x * normalizeFactor) + 0.5f), 0.f, 1.f);
423 delta.y = Clamp(((delta.y * normalizeFactor) + 0.5f), 0.f, 1.f);
424 delta.z = Clamp(((delta.z * normalizeFactor) + 0.5f), 0.f, 1.f);
427 // Calculate and store the unnormalize factor.
428 blendShapeUnnormalizeFactor = 1.f / normalizeFactor;
431 if (blendShape.normals.IsDefined())
433 geometryBufferIndex += numberOfVertices;
436 if (blendShape.tangents.IsDefined())
438 geometryBufferIndex += numberOfVertices;
445 MeshDefinition::SparseBlob::SparseBlob(const Blob& indices, const Blob& values, uint32_t count)
451 MeshDefinition::Accessor::Accessor(const MeshDefinition::Blob& blob,
452 const MeshDefinition::SparseBlob& sparse)
454 mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{sparse} : nullptr}
457 void MeshDefinition::Blob::ApplyMinMax(const std::vector<float>& min, const std::vector<float>& max,
458 uint32_t count, float* values)
460 DALI_ASSERT_DEBUG(max.size() == min.size() || max.size() * min.size() == 0);
461 const auto numComponents = std::max(min.size(), max.size());
463 using ClampFn = void(*)(const float*, const float*, uint32_t, float&);
464 ClampFn clampFn = min.empty() ?
466 static_cast<ClampFn>(nullptr) :
467 [](const float* min, const float* max, uint32_t i, float& value) {
468 value = std::min(max[i], value);
471 [](const float* min, const float* max, uint32_t i, float& value) {
472 value = std::max(min[i], value);
474 [](const float* min, const float* max, uint32_t i, float& value) {
475 value = std::min(std::max(min[i], value), max[i]);
478 auto end = values + count * numComponents;
479 while (values != end)
481 auto nextElement = values + numComponents;
483 while (values != nextElement)
485 clampFn(min.data(), max.data(), i, *values);
492 uint32_t MeshDefinition::Blob::GetBufferSize() const
494 return IsConsecutive() ? mLength : (mLength * mElementSizeHint / mStride);
497 void MeshDefinition::Blob::ApplyMinMax(uint32_t count, float* values) const
499 ApplyMinMax(mMin, mMax, count, values);
502 void MeshDefinition::RawData::Attrib::AttachBuffer(Geometry& g) const
504 Property::Map attribMap;
505 attribMap[mName] = mType;
506 VertexBuffer attribBuffer = VertexBuffer::New(attribMap);
507 attribBuffer.SetData(mData.data(), mNumElements);
509 g.AddVertexBuffer(attribBuffer);
512 bool MeshDefinition::IsQuad() const
514 return CaseInsensitiveStringCompare("quad", mUri);
517 bool MeshDefinition::IsSkinned() const
519 return mJoints0.IsDefined() && mWeights0.IsDefined();
522 bool MeshDefinition::HasBlendShapes() const
524 return !mBlendShapes.empty();
527 void MeshDefinition::RequestNormals()
529 mNormals.mBlob.mLength = mPositions.mBlob.GetBufferSize();
532 void MeshDefinition::RequestTangents()
534 mTangents.mBlob.mLength = mNormals.mBlob.GetBufferSize();
537 MeshDefinition::RawData
538 MeshDefinition::LoadRaw(const std::string& modelsPath) const
546 const std::string meshPath = modelsPath + mUri;
547 std::ifstream binFile(meshPath, std::ios::binary);
550 ExceptionFlinger(ASSERT_LOCATION) << "Failed to read geometry data from '" << meshPath << "'";
553 if (mIndices.IsDefined())
555 if (MaskMatch(mFlags, U32_INDICES))
557 DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(uint32_t) == 0) ||
558 mIndices.mBlob.mStride >= sizeof(uint32_t)) &&
559 "Index buffer length not a multiple of element size");
560 const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint32_t);
561 raw.mIndices.resize(indexCount * 2); // NOTE: we need space for uint32_ts initially.
562 if (!ReadAccessor(mIndices, binFile, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
564 ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << meshPath << "'.";
567 auto u16s = raw.mIndices.data();
568 auto u32s = reinterpret_cast<uint32_t*>(raw.mIndices.data());
569 auto end = u32s + indexCount;
572 *u16s = static_cast<uint16_t>(*u32s);
577 raw.mIndices.resize(indexCount);
581 DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(unsigned short) == 0) ||
582 mIndices.mBlob.mStride >= sizeof(unsigned short)) &&
583 "Index buffer length not a multiple of element size");
584 raw.mIndices.resize(mIndices.mBlob.mLength / sizeof(unsigned short));
585 if (!ReadAccessor(mIndices, binFile, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
587 ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << meshPath << "'.";
592 std::vector<Vector3> positions;
593 if (mPositions.IsDefined())
595 DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % sizeof(Vector3) == 0) ||
596 mPositions.mBlob.mStride >= sizeof(Vector3)) &&
597 "Position buffer length not a multiple of element size");
598 const auto bufferSize = mPositions.mBlob.GetBufferSize();
599 std::vector<uint8_t> buffer(bufferSize);
600 if (!ReadAccessor(mPositions, binFile, buffer.data()))
602 ExceptionFlinger(ASSERT_LOCATION) << "Failed to read positions from '" << meshPath << "'.";
605 uint32_t numVector3 = bufferSize / sizeof(Vector3);
606 mPositions.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
608 if (HasBlendShapes())
610 positions.resize(numVector3);
611 std::copy(buffer.data(), buffer.data() + buffer.size(), reinterpret_cast<uint8_t*>(positions.data()));
614 raw.mAttribs.push_back({ "aPosition", Property::VECTOR3, numVector3, std::move(buffer) });
617 const auto isTriangles = mPrimitiveType == Geometry::TRIANGLES;
618 auto hasNormals = mNormals.IsDefined();
621 DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % sizeof(Vector3) == 0) ||
622 mNormals.mBlob.mStride >= sizeof(Vector3)) &&
623 "Normal buffer length not a multiple of element size");
624 const auto bufferSize = mNormals.mBlob.GetBufferSize();
625 std::vector<uint8_t> buffer(bufferSize);
626 if (!ReadAccessor(mNormals, binFile, buffer.data()))
628 ExceptionFlinger(ASSERT_LOCATION) << "Failed to read normals from '" << meshPath << "'.";
631 mNormals.mBlob.ApplyMinMax(bufferSize / sizeof(Vector3), reinterpret_cast<float*>(buffer.data()));
633 raw.mAttribs.push_back({ "aNormal", Property::VECTOR3,
634 static_cast<uint32_t>(bufferSize / sizeof(Vector3)), std::move(buffer) });
636 else if (mNormals.mBlob.mLength != 0 && isTriangles)
638 DALI_ASSERT_DEBUG(mNormals.mBlob.mLength == mPositions.mBlob.GetBufferSize());
639 GenerateNormals(raw);
643 const auto hasUvs = mTexCoords.IsDefined();
646 DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % sizeof(Vector2) == 0) ||
647 mTexCoords.mBlob.mStride >= sizeof(Vector2)) &&
648 "Normal buffer length not a multiple of element size");
649 const auto bufferSize = mTexCoords.mBlob.GetBufferSize();
650 std::vector<uint8_t> buffer(bufferSize);
651 if (!ReadAccessor(mTexCoords, binFile, buffer.data()))
653 ExceptionFlinger(ASSERT_LOCATION) << "Failed to read uv-s from '" << meshPath << "'.";
656 const auto uvCount = bufferSize / sizeof(Vector2);
657 if (MaskMatch(mFlags, FLIP_UVS_VERTICAL))
659 auto uv = reinterpret_cast<Vector2*>(buffer.data());
660 auto uvEnd = uv + uvCount;
663 uv->y = 1.0f - uv->y;
668 mTexCoords.mBlob.ApplyMinMax(bufferSize / sizeof(Vector2), reinterpret_cast<float*>(buffer.data()));
670 raw.mAttribs.push_back({ "aTexCoord", Property::VECTOR2, static_cast<uint32_t>(uvCount),
671 std::move(buffer) });
674 if (mTangents.IsDefined())
676 DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % sizeof(Vector3) == 0) ||
677 mTangents.mBlob.mStride >= sizeof(Vector3)) &&
678 "Tangents buffer length not a multiple of element size");
679 const auto bufferSize = mTangents.mBlob.GetBufferSize();
680 std::vector<uint8_t> buffer(bufferSize);
681 if (!ReadAccessor(mTangents, binFile, buffer.data()))
683 ExceptionFlinger(ASSERT_LOCATION) << "Failed to read tangents from '" << meshPath << "'.";
686 mTangents.mBlob.ApplyMinMax(bufferSize / sizeof(Vector3), reinterpret_cast<float*>(buffer.data()));
688 raw.mAttribs.push_back({ "aTangent", Property::VECTOR3,
689 static_cast<uint32_t>(bufferSize / sizeof(Vector3)), std::move(buffer) });
691 else if (mTangents.mBlob.mLength != 0 && hasNormals && isTriangles)
693 DALI_ASSERT_DEBUG(mTangents.mBlob.mLength == mNormals.mBlob.GetBufferSize());
694 hasUvs ? GenerateTangentsWithUvs(raw) : GenerateTangents(raw);
699 if (MaskMatch(mFlags, U16_JOINT_IDS))
701 DALI_ASSERT_ALWAYS(((mJoints0.mBlob.mLength % sizeof(Uint16Vector4) == 0) ||
702 mJoints0.mBlob.mStride >= sizeof(Uint16Vector4)) &&
703 "Joints buffer length not a multiple of element size");
704 const auto inBufferSize = mJoints0.mBlob.GetBufferSize();
705 std::vector<uint8_t> buffer(inBufferSize * 2);
706 auto u16s = buffer.data() + inBufferSize;
707 if (!ReadAccessor(mJoints0, binFile, u16s))
709 ExceptionFlinger(ASSERT_LOCATION) << "Failed to read joints from '" << meshPath << "'.";
712 auto floats = reinterpret_cast<float*>(buffer.data());
713 auto end = u16s + inBufferSize;
716 auto value = *reinterpret_cast<uint16_t*>(u16s);
717 *floats = static_cast<float>(value);
719 u16s += sizeof(uint16_t);
722 raw.mAttribs.push_back({ "aJoints", Property::VECTOR4,
723 static_cast<uint32_t>(buffer.size() / sizeof(Vector4)), std::move(buffer) });
727 DALI_ASSERT_ALWAYS(((mJoints0.mBlob.mLength % sizeof(Vector4) == 0) ||
728 mJoints0.mBlob.mStride >= sizeof(Vector4)) &&
729 "Joints buffer length not a multiple of element size");
730 const auto bufferSize = mJoints0.mBlob.GetBufferSize();
731 std::vector<uint8_t> buffer(bufferSize);
732 if (!ReadAccessor(mJoints0, binFile, buffer.data()))
734 ExceptionFlinger(ASSERT_LOCATION) << "Failed to read joints from '" << meshPath << "'.";
737 raw.mAttribs.push_back({ "aJoints", Property::VECTOR4,
738 static_cast<uint32_t>(bufferSize / sizeof(Vector4)), std::move(buffer) });
741 DALI_ASSERT_ALWAYS(((mWeights0.mBlob.mLength % sizeof(Vector4) == 0) ||
742 mWeights0.mBlob.mStride >= sizeof(Vector4)) &&
743 "Weights buffer length not a multiple of element size");
744 const auto bufferSize = mWeights0.mBlob.GetBufferSize();
745 std::vector<uint8_t> buffer(bufferSize);
746 if (!ReadAccessor(mWeights0, binFile, buffer.data()))
748 ExceptionFlinger(ASSERT_LOCATION) << "Failed to read weights from '" << meshPath << "'.";
751 raw.mAttribs.push_back({ "aWeights", Property::VECTOR4,
752 static_cast<uint32_t>(bufferSize / sizeof(Vector4)), std::move(buffer) });
755 // Calculate the Blob for the blend shapes.
756 Blob blendShapesBlob;
757 blendShapesBlob.mOffset = std::numeric_limits<unsigned int>::max();
758 blendShapesBlob.mLength = 0u;
760 for (const auto& blendShape : mBlendShapes)
762 for (auto i : { &blendShape.deltas, &blendShape.normals, &blendShape.tangents })
766 blendShapesBlob.mOffset = std::min(blendShapesBlob.mOffset, i->mBlob.mOffset);
767 blendShapesBlob.mLength += i->mBlob.mLength;
772 if (HasBlendShapes())
774 const uint32_t numberOfVertices = mPositions.mBlob.mLength / sizeof(Vector3);
776 // Calculate the size of one buffer inside the texture.
777 raw.mBlendShapeBufferOffset = numberOfVertices;
779 bool calculateGltf2BlendShapes = false;
780 uint32_t textureWidth = 0u;
781 uint32_t textureHeight = 0u;
783 if (!mBlendShapeHeader.IsDefined())
785 CalculateTextureSize(blendShapesBlob.mLength / sizeof(Vector3), textureWidth, textureHeight);
786 calculateGltf2BlendShapes = true;
791 ReadBlob(mBlendShapeHeader, binFile, reinterpret_cast<uint8_t*>(header));
792 textureWidth = header[0u];
793 textureHeight = header[1u];
796 const uint32_t numberOfBlendShapes = mBlendShapes.size();
797 raw.mBlendShapeUnnormalizeFactor.Resize(numberOfBlendShapes);
799 Devel::PixelBuffer geometryPixelBuffer = Devel::PixelBuffer::New(textureWidth, textureHeight, Pixel::RGB32F);
800 uint8_t* geometryBuffer = geometryPixelBuffer.GetBuffer();
802 if (calculateGltf2BlendShapes)
804 CalculateGltf2BlendShapes(geometryBuffer, binFile, mBlendShapes, numberOfVertices, raw.mBlendShapeUnnormalizeFactor[0u]);
808 Blob unnormalizeFactorBlob;
809 unnormalizeFactorBlob.mLength = sizeof(float) * ((BlendShapes::Version::VERSION_2_0 == mBlendShapeVersion) ? 1u : numberOfBlendShapes);
811 if (blendShapesBlob.IsDefined())
813 if (ReadBlob(blendShapesBlob, binFile, geometryBuffer))
815 unnormalizeFactorBlob.mOffset = blendShapesBlob.mOffset + blendShapesBlob.mLength;
819 // Read the unnormalize factors.
820 if (unnormalizeFactorBlob.IsDefined())
822 ReadBlob(unnormalizeFactorBlob, binFile, reinterpret_cast<uint8_t*>(&raw.mBlendShapeUnnormalizeFactor[0u]));
825 raw.mBlendShapeData = Devel::PixelBuffer::Convert(geometryPixelBuffer);
831 MeshGeometry MeshDefinition::Load(RawData&& raw) const
833 MeshGeometry meshGeometry;
834 meshGeometry.geometry = Geometry::New();
835 meshGeometry.geometry.SetType(mPrimitiveType);
837 if (IsQuad()) // TODO: do this in raw data; provide MakeTexturedQuadGeometry() that only creates buffers.
839 auto options = MaskMatch(mFlags, FLIP_UVS_VERTICAL) ? TexturedQuadOptions::FLIP_VERTICAL : 0;
840 meshGeometry.geometry = MakeTexturedQuadGeometry(options);
844 if (!raw.mIndices.empty())
846 meshGeometry.geometry.SetIndexBuffer(raw.mIndices.data(), raw.mIndices.size());
849 for (auto& a : raw.mAttribs)
851 a.AttachBuffer(meshGeometry.geometry);
854 if (HasBlendShapes())
856 meshGeometry.blendShapeBufferOffset = raw.mBlendShapeBufferOffset;
857 meshGeometry.blendShapeUnnormalizeFactor = std::move(raw.mBlendShapeUnnormalizeFactor);
859 meshGeometry.blendShapeGeometry = Texture::New( TextureType::TEXTURE_2D,
860 raw.mBlendShapeData.GetPixelFormat(),
861 raw.mBlendShapeData.GetWidth(),
862 raw.mBlendShapeData.GetHeight());
863 meshGeometry.blendShapeGeometry.Upload(raw.mBlendShapeData);