51bool MDL::open(
const std::byte* data, std::size_t size) {
52 BufferStreamReadOnly stream{data, size};
54 if (stream.read<int32_t>() !=
MDL_ID) {
58 if (stream.read(this->version); this->version < 44 || this->version > 49) {
73 this->
flags =
static_cast<Flags>(stream.read<int32_t>());
75 const auto boneCount = stream.read<int32_t>();
76 const auto boneOffset = stream.read<int32_t>();
78 const auto boneControllerCount = stream.read<int32_t>();
79 const auto boneControllerOffset = stream.read<int32_t>();
81 const auto hitboxSetCount = stream.read<int32_t>();
82 const auto hitboxSetOffset = stream.read<int32_t>();
84 const auto animDescCount = stream.read<int32_t>();
85 const auto animDescOffset = stream.read<int32_t>();
87 const auto sequenceDescCount = stream.read<int32_t>();
88 const auto sequenceDescOffset = stream.read<int32_t>();
94 const auto materialCount = stream.read<int32_t>();
95 const auto materialOffset = stream.read<int32_t>();
97 const auto materialDirCount = stream.read<int32_t>();
98 const auto materialDirOffset = stream.read<int32_t>();
100 const auto skinReferenceCount = stream.read<int32_t>();
101 const auto skinReferenceFamilyCount = stream.read<int32_t>();
102 const auto skinReferenceOffset = stream.read<int32_t>();
104 const auto bodyPartCount = stream.read<int32_t>();
105 const auto bodyPartOffset = stream.read<int32_t>();
107 const auto attachmentCount = stream.read<int32_t>();
108 const auto attachmentOffset = stream.read<int32_t>();
110 const auto localNodeCount = stream.read<int32_t>();
111 const auto localNodeIndex = stream.read<int32_t>();
112 const auto localNodeNameIndex = stream.read<int32_t>();
114 const auto flexDescCount = stream.read<int32_t>();
115 const auto flexDescIndex = stream.read<int32_t>();
116 const auto flexControllerCount = stream.read<int32_t>();
117 const auto flexControllerIndex = stream.read<int32_t>();
118 const auto flexRulesCount = stream.read<int32_t>();
119 const auto flexRulesIndex = stream.read<int32_t>();
120 const auto ikChainCount = stream.read<int32_t>();
121 const auto ikChainIndex = stream.read<int32_t>();
123 const auto mouthsCount = stream.read<int32_t>();
124 const auto mouthsIndex = stream.read<int32_t>();
126 const auto localPoseParamCount = stream.read<int32_t>();
127 const auto localPoseParamIndex = stream.read<int32_t>();
129 const auto surfacePropertyIndex = stream.read<int32_t>();
130 const auto keyValueIndex = stream.read<int32_t>();
131 const auto keyValueCount = stream.read<int32_t>();
133 const auto localIKAutoplayLockCount = stream.read<int32_t>();
134 const auto localIKAutoplayLockIndex = stream.read<int32_t>();
140 const auto includeModelCount = stream.read<int32_t>();
141 const auto includeModelIndex = stream.read<int32_t>();
142 stream.skip<int32_t>();
145 const auto animationBlocksNameIndex = stream.read<int32_t>();
146 const auto animationBlocksCount = stream.read<int32_t>();
147 const auto animationBlocksIndex = stream.read<int32_t>();
148 stream.skip<int32_t>();
150 const auto boneTableNameIndex = stream.read<int32_t>();
161 const auto flexControllerUICount = stream.read<int32_t>();
162 const auto flexControllerUIIndex = stream.read<int32_t>();
176 .read(this->
header2.srcBoneTransformCount)
177 .read(this->
header2.srcBoneTransformIndex)
178 .read(this->
header2.illumPositionAttachmentIndex)
179 .read(this->
header2.maxEyeDeflection)
180 .read(this->
header2.linearBoneIndex)
182 .read(this->
header2.boneFlexDriverCount)
183 .read(this->
header2.boneFlexDriverIndex);
184 stream.skip<int32_t>(56);
187 for (
int i = 0; i < this->
header2.srcBoneTransformCount; i++) {
188 const auto srcBoneTransformPos = this->
studioHdr2Index + this->
header2.srcBoneTransformIndex + i * (
sizeof(int32_t) +
sizeof(math::Mat3x4f) * 2);
189 if (srcBoneTransformPos + (
sizeof(int32_t) +
sizeof(math::Mat3x4f) * 2) > stream.size()) {
194 stream.seek_u(srcBoneTransformPos);
195 const auto nameOffset = stream.read<int32_t>();
196 const auto nameAbsOffset = srcBoneTransformPos + nameOffset;
197 if (nameOffset != 0 && nameAbsOffset > 0 && nameAbsOffset < stream.size()) {
198 stream.seek_u(nameAbsOffset)
199 .read(srcBoneTransform.name)
200 .seek_u(srcBoneTransformPos +
sizeof(int32_t));
204 .read(srcBoneTransform.pretransform)
205 .read(srcBoneTransform.posttransform);
208 if (this->
header2.linearBoneIndex != 0) {
210 if (linearBoneOffset +
sizeof(int32_t) * 16 <= stream.size()) {
214 stream.seek_u(linearBoneOffset)
217 const auto flagsIndex = stream.read<int32_t>();
218 const auto parentIndex = stream.read<int32_t>();
219 const auto posIndex = stream.read<int32_t>();
220 const auto quatIndex = stream.read<int32_t>();
221 const auto rotIndex = stream.read<int32_t>();
222 const auto poseToBoneIndex = stream.read<int32_t>();
223 const auto posScaleIndex = stream.read<int32_t>();
224 const auto rotScaleIndex = stream.read<int32_t>();
225 const auto qAlignmentIndex = stream.read<int32_t>();
226 stream.skip<int32_t>(6);
229 stream.seek_u(linearBoneOffset + flagsIndex);
230 for (
int i = 0; i < lb.boneCount; i++) {
231 lb.flags.push_back(stream.read<int32_t>());
234 stream.seek_u(linearBoneOffset + parentIndex);
235 for (
int i = 0; i < lb.boneCount; i++) {
236 lb.parent.push_back(stream.read<int32_t>());
239 stream.seek_u(linearBoneOffset + posIndex);
240 for (
int i = 0; i < lb.boneCount; i++) {
241 lb.position.push_back(stream.read<math::Vec3f>());
244 stream.seek_u(linearBoneOffset + quatIndex);
245 for (
int i = 0; i < lb.boneCount; i++) {
246 lb.quaternion.push_back(stream.read<
math::Quat>());
249 stream.seek_u(linearBoneOffset + rotIndex);
250 for (
int i = 0; i < lb.boneCount; i++) {
251 lb.rotation.push_back(stream.read<math::Vec3f>());
254 stream.seek_u(linearBoneOffset + poseToBoneIndex);
255 for (
int i = 0; i < lb.boneCount; i++) {
256 lb.poseToBone.push_back(stream.read<math::Mat3x4f>());
259 stream.seek_u(linearBoneOffset + posScaleIndex);
260 for (
int i = 0; i < lb.boneCount; i++) {
261 lb.positionScale.push_back(stream.read<math::Vec3f>());
264 stream.seek_u(linearBoneOffset + rotScaleIndex);
265 for (
int i = 0; i < lb.boneCount; i++) {
266 lb.rotationScale.push_back(stream.read<math::Vec3f>());
269 stream.seek_u(linearBoneOffset + qAlignmentIndex);
270 for (
int i = 0; i < lb.boneCount; i++) {
271 lb.quaternionAlignment.push_back(stream.read<
math::Quat>());
276 for (
int i = 0; i < this->
header2.boneFlexDriverCount; i++) {
277 const auto boneFlexDriverPos = this->
studioHdr2Index + this->
header2.boneFlexDriverIndex + i * (
sizeof(int32_t) * 6);
278 if (boneFlexDriverPos + (
sizeof(int32_t) * 6) > stream.size()) {
282 stream.seek_u(boneFlexDriverPos)
283 .read(boneFlexDriver.boneIndex);
285 const auto controlCount = stream.read<int32_t>();
286 const auto controlIndex = stream.read<int32_t>();
287 stream.skip<int32_t>(3);
289 for (
int j = 0; j < controlCount; j++) {
290 const auto controlPos = boneFlexDriverPos + controlIndex + j * (
sizeof(int32_t) * 2 +
sizeof(float) * 2);
291 if (controlPos + (
sizeof(int32_t) * 2 +
sizeof(
float) * 2) > stream.size()) {
294 auto& control = boneFlexDriver.controls.emplace_back();
295 stream.seek_u(controlPos)
296 .read(control.boneComponent)
297 .read(control.flexControllerIndex)
306 stream.seek(boneOffset);
307 for (
int i = 0; i < boneCount; i++) {
308 auto& bone = this->
bones.emplace_back();
313 .read(bone.boneController)
315 .read(bone.rotationQuat)
316 .read(bone.rotationEuler)
317 .read(bone.positionScale)
318 .read(bone.rotationScale)
319 .read(bone.poseToBose)
320 .read(bone.alignment)
323 .read(bone.procIndex)
324 .read(bone.physicsBone);
334 stream.read(bone.contents);
337 stream.skip<int32_t>(8);
340 stream.seek(boneControllerOffset);
341 for (
int i = 0; i < boneControllerCount; i++) {
345 stream.skip<int32_t>(8);
347 for (
int i = 0; i < hitboxSetCount; i++) {
348 const auto hitboxSetPos = hitboxSetOffset + i * (
sizeof(int32_t) * 3);
349 stream.seek_u(hitboxSetPos);
351 auto& hitboxSet = this->
hitboxSets.emplace_back();
354 const auto hitboxCount = stream.read<int32_t>();
355 const auto hitboxOffset = stream.read<int32_t>();
357 for (
int j = 0; j < hitboxCount; j++) {
358 const auto hitboxPos = hitboxOffset + j * (
sizeof(int32_t) * 11 +
sizeof(math::Vec3f) * 2);
359 if (!seekAndValidate(stream, hitboxSetPos + hitboxPos)) {
363 auto& hitbox = hitboxSet.hitboxes.emplace_back();
368 .read(hitbox.bboxMin)
369 .read(hitbox.bboxMax);
374 stream.skip<int32_t>();
378 stream.skip<int32_t>(8);
382 stream.seek(animDescOffset);
383 for (
int i = 0; i < animDescCount; i++) {
384 const auto animDescPos = animDescOffset + i * (
sizeof(int32_t) * 22 +
sizeof(int16_t) * 2 +
sizeof(float) * 2);
385 stream.seek_u(animDescPos);
387 auto& animDesc = this->
animations.emplace_back();
389 stream.skip<int32_t>();
396 .read(animDesc.flags)
397 .read(animDesc.frameCount);
399 const auto movementCount = stream.read<int32_t>();
400 const auto movementIndex = stream.read<int32_t>();
401 stream.skip<int32_t>(6);
404 .read(animDesc.animBlock)
405 .read(animDesc.animIndex);
407 const auto ikRuleCount = stream.read<int32_t>();
408 const auto ikRuleIndex = stream.read<int32_t>();
410 stream.read(animDesc.animBlockIKRuleIndex);
412 const auto localHierarchyCount = stream.read<int32_t>();
413 const auto localHierarchyIndex = stream.read<int32_t>();
415 const auto sectionIndex = stream.read<int32_t>();
416 stream.read(animDesc.sectionFrames);
421 stream.read(animDesc.zeroFrameSpan)
422 .read(animDesc.zeroFrameCount)
423 .read(animDesc.zeroFrameIndex)
424 .read(animDesc.zeroFrameStallTime);
428 if (animDesc.animIndex != 0 && animDesc.animBlock == 0) {
429 const auto animDataPos = animDescPos + animDesc.animIndex;
430 if (!seekAndValidate(stream, animDataPos)) {
433 const auto savedPos = stream.tell();
438 const auto boneAnimPos = stream.tell();
440 auto& boneAnim = animDesc.boneAnimations.emplace_back();
443 .read(boneAnim.flags);
445 if (boneAnim.bone == 255) {
446 animDesc.boneAnimations.pop_back();
450 const auto nextOffset = stream.read<int16_t>();
467 boneAnim.animRotationPtr = rotPtr;
469 const auto ptrPos = stream.tell();
472 for (uint8_t idx = 0; idx < rotPtr.size(); idx++) {
473 const auto comp = rotPtr[idx];
475 if (!seekAndValidate(stream, ptrPos -
sizeof(
AnimValuePtr) + comp)) {
478 readAnimValueRLE(stream, animDesc.frameCount, boneAnim.animRotationData);
482 stream.seek_u(ptrPos);
489 boneAnim.animPositionPtr = posPtr;
491 const auto ptrPos = stream.tell();
494 for (uint8_t idx = 0; idx < posPtr.size(); idx++) {
495 const auto comp = posPtr[idx];
497 if (!seekAndValidate(stream, ptrPos -
sizeof(
AnimValuePtr) + comp)) {
500 readAnimValueRLE(stream, animDesc.frameCount, boneAnim.animPositionData);
504 stream.seek_u(ptrPos);
507 if (nextOffset == 0) {
510 if (!seekAndValidate(stream, boneAnimPos + nextOffset)) {
515 stream.seek_u(savedPos);
518 const auto movementDataPos = animDescPos + movementIndex;
519 if (!seekAndValidate(stream, movementDataPos)) {
523 for (
int j = 0; j < movementCount; j++) {
524 auto& movement = animDesc.movements.emplace_back();
525 stream.read(movement.endFrame);
530 .read(movement.velocityStart)
531 .read(movement.velocityEnd)
532 .read(movement.yawEnd)
533 .read(movement.movement)
534 .read(movement.relativePosition);
537 if (ikRuleIndex != 0 && animDesc.animBlock == 0) {
538 const auto ikRuleDataPos = animDescPos + ikRuleIndex;
539 if (!seekAndValidate(stream, ikRuleDataPos)) {
543 for (
int j = 0; j < ikRuleCount; j++) {
544 const auto ikRulePos = ikRuleDataPos + j * (
sizeof(int32_t) * 20 +
sizeof(float) * 11 +
sizeof(math::Vec3f) +
sizeof(
math::Quat));
545 stream.seek_u(ikRulePos);
547 auto& ikRule = animDesc.ikRules.emplace_back();
561 const auto compressedIKErrorIndex = stream.read<int32_t>();
562 stream.skip<int32_t>();
565 .read(ikRule.iStart);
567 const auto ikErrorIndex = stream.read<int32_t>();
576 .read(ikRule.contact)
585 stream.skip<int32_t>(7);
588 if (compressedIKErrorIndex != 0) {
589 const auto compErrorPos = ikRulePos + compressedIKErrorIndex;
590 const auto savedPos = stream.tell();
591 stream.seek_u(compErrorPos);
595 .read(ikRule.compressedIKError->scale)
596 .read(ikRule.compressedIKError->offset);
598 const auto compErrorDataPos = stream.tell();
599 for (uint8_t idx = 0; idx < ikRule.compressedIKError->offset.size(); idx++) {
600 const auto k = ikRule.compressedIKError->offset[idx];
602 if (!seekAndValidate(stream, compErrorDataPos + k)) {
605 readAnimValueRLE(stream, animDesc.frameCount, ikRule.compressedIKError->animValues);
609 stream.seek_u(savedPos);
613 if (ikErrorIndex != 0) {
614 const auto ikErrorPos = ikRulePos + ikErrorIndex;
615 const auto savedPos = stream.tell();
616 stream.seek_u(ikErrorPos);
618 const int errorFrameCount = animDesc.frameCount - ikRule.iStart;
619 ikRule.ikErrors.reserve(errorFrameCount);
621 for (
int k = 0; k < errorFrameCount; k++) {
622 auto& ikError = ikRule.ikErrors.emplace_back();
624 .read(ikError.position)
625 .read(ikError.rotation);
628 stream.seek_u(savedPos);
633 if (localHierarchyIndex != 0 && animDesc.animBlock == 0) {
634 for (
int j = 0; j < localHierarchyCount; j++) {
635 const auto localHierarchyPos = animDescPos + localHierarchyIndex + j * (
sizeof(int32_t) * 2 +
sizeof(float) * 4 +
sizeof(int32_t) * 6);
636 stream.seek_u(localHierarchyPos);
638 auto& localHierarchy = animDesc.localHierarchies.emplace_back();
640 .read(localHierarchy.bone)
641 .read(localHierarchy.newParent)
642 .read(localHierarchy.start)
643 .read(localHierarchy.peak)
644 .read(localHierarchy.tail)
645 .read(localHierarchy.end)
646 .read(localHierarchy.startFrame);
648 const auto localAnimIndex = stream.read<int32_t>();
649 stream.skip<int32_t>(4);
651 if (localAnimIndex != 0) {
652 const auto compErrorPos = localHierarchyPos + localAnimIndex;
653 stream.seek_u(compErrorPos);
657 .read(localHierarchy.compressedIKError->scale)
658 .read(localHierarchy.compressedIKError->offset);
660 const auto compErrorDataPos = stream.tell();
661 for (uint8_t idx = 0; idx < localHierarchy.compressedIKError->offset.size(); idx++) {
662 const auto k = localHierarchy.compressedIKError->offset[idx];
664 if (!seekAndValidate(stream, compErrorDataPos + k)) {
667 readAnimValueRLE(stream, animDesc.frameCount, localHierarchy.compressedIKError->animValues);
674 if (sectionIndex != 0 && animDesc.sectionFrames > 0) {
677 const int sectionCount = animDesc.frameCount / animDesc.sectionFrames + 2;
678 for (
int j = 0; j < sectionCount; j++) {
679 const auto sectionPos = animDescPos + sectionIndex + j *
sizeof(
AnimSection);
680 stream.seek_u(sectionPos);
682 auto& section = animDesc.sections.emplace_back();
684 .read(section.animBlock)
685 .read(section.animIndex);
690 stream.seek(sequenceDescOffset);
691 for (
int i = 0; i < sequenceDescCount; i++) {
692 const auto sequenceDescPos = sequenceDescOffset + i * (
sizeof(int32_t) * 38 +
sizeof(float) * 9 +
sizeof(math::Vec3f) * 2);
693 stream.seek_u(sequenceDescPos);
695 auto& sequenceDesc = this->
sequences.emplace_back();
697 stream.skip<int32_t>();
701 .read(sequenceDesc.flags)
702 .read(sequenceDesc.activity)
703 .read(sequenceDesc.activityWeight);
705 const auto eventCount = stream.read<int32_t>();
706 const auto eventIndex = stream.read<int32_t>();
709 .read(sequenceDesc.boundingBoxMin)
710 .read(sequenceDesc.boundingBoxMax)
711 .read(sequenceDesc.blendCount);
713 const auto animIndexIndex = stream.read<int32_t>();
716 .read(sequenceDesc.movementIndex)
717 .read(sequenceDesc.groupSize)
718 .read(sequenceDesc.paramIndex)
719 .read(sequenceDesc.paramStart)
720 .read(sequenceDesc.paramEnd)
721 .read(sequenceDesc.paramParent)
722 .read(sequenceDesc.fadeInTime)
723 .read(sequenceDesc.fadeOutTime)
724 .read(sequenceDesc.localEntryNode)
725 .read(sequenceDesc.localExitNode)
726 .read(sequenceDesc.nodeFlags)
727 .read(sequenceDesc.entryPhase)
728 .read(sequenceDesc.exitPhase)
729 .read(sequenceDesc.lastFrame)
730 .read(sequenceDesc.nextSequence)
731 .read(sequenceDesc.pose)
732 .read(sequenceDesc.ikRuleCount);
734 const auto autoLayerCount = stream.read<int32_t>();
735 const auto autoLayerIndex = stream.read<int32_t>();
737 const auto weightListIndex = stream.read<int32_t>();
738 const auto poseKeyIndex = stream.read<int32_t>();
740 const auto ikLockCount = stream.read<int32_t>();
741 const auto ikLockIndex = stream.read<int32_t>();
743 const auto seqKeyValueIndex = stream.read<int32_t>();
744 const auto seqKeyValueSize = stream.read<int32_t>();
746 stream.read(sequenceDesc.cyclePoseIndex);
748 const auto activityModifierIndex = stream.read<int32_t>();
749 const auto activityModifierCount = stream.read<int32_t>();
751 stream.skip<int32_t>(5);
753 if (animIndexIndex != 0 && sequenceDesc.groupSize[0] > 0 && sequenceDesc.groupSize[1] > 0) {
754 stream.seek_u(sequenceDescPos + animIndexIndex);
755 const int blendCount = sequenceDesc.groupSize[0] * sequenceDesc.groupSize[1];
756 for (
int j = 0; j < blendCount; j++) {
757 sequenceDesc.animIndices.push_back(stream.read<int16_t>());
762 if (weightListIndex != 0 && boneCount > 0) {
763 stream.seek_u(sequenceDescPos + weightListIndex);
764 for (
int j = 0; j < boneCount; j++) {
765 sequenceDesc.boneWeights.push_back(stream.read<
float>());
769 if (poseKeyIndex != 0) {
770 stream.seek_u(sequenceDescPos + poseKeyIndex);
774 const int poseKeyCount = 2 * sequenceDesc.groupSize[0];
775 for (
int j = 0; j < poseKeyCount; j++) {
776 sequenceDesc.poseKeys.push_back(stream.read<
float>());
780 if (activityModifierIndex != 0) {
781 for (
int j = 0; j < activityModifierCount; j++) {
782 const auto modifierPos = sequenceDescPos + activityModifierIndex + j *
sizeof(int32_t);
783 stream.seek_u(modifierPos);
784 auto& modifier = sequenceDesc.activityModifiers.emplace_back();
789 const auto ikLockDataPos = sequenceDescPos + ikLockIndex;
790 stream.seek_u(ikLockDataPos);
792 for (
int j = 0; j < ikLockCount; j++) {
793 auto& ikLock = sequenceDesc.ikLocks.emplace_back();
796 .read(ikLock.posWeight)
797 .read(ikLock.localQWeight)
799 stream.skip<int32_t>(4);
802 const auto eventDataPos = sequenceDescPos + eventIndex;
803 stream.seek_u(eventDataPos);
805 for (
int j = 0; j < eventCount; j++) {
806 auto&
event = sequenceDesc.events.emplace_back();
812 .read(event.options, 64);
815 sizeof(
float) +
sizeof(int32_t) * 2 + 64);
818 const auto autoLayerDataPos = sequenceDescPos + autoLayerIndex;
819 stream.seek_u(autoLayerDataPos);
821 for (
int j = 0; j < autoLayerCount; j++) {
822 auto& autoLayer = sequenceDesc.autoLayers.emplace_back();
824 .read(autoLayer.sequence)
825 .read(autoLayer.pose)
826 .read(autoLayer.flags)
827 .read(autoLayer.start)
828 .read(autoLayer.peak)
829 .read(autoLayer.tail)
830 .read(autoLayer.end);
833 if (seqKeyValueSize > 0 && seqKeyValueIndex != 0) {
834 const auto seqKeyValueDataPos = sequenceDescPos + seqKeyValueIndex;
835 stream.seek_u(seqKeyValueDataPos).read(sequenceDesc.keyValues, seqKeyValueSize);
839 stream.seek(materialOffset);
840 for (
int i = 0; i < materialCount; i++) {
841 auto& material = this->
materials.emplace_back();
843 stream.read(material.flags);
846 stream.skip<int32_t>();
848 stream.skip<int32_t>(13);
851 stream.seek(materialDirOffset);
852 for (
int i = 0; i < materialDirCount; i++) {
857 stream.seek(skinReferenceOffset);
858 for (
int i = 0; i < skinReferenceFamilyCount; i++) {
859 std::vector<int16_t> skinFamily;
860 skinFamily.reserve(skinReferenceCount);
861 for (
int j = 0; j < skinReferenceCount; j++) {
862 skinFamily.push_back(stream.read<int16_t>());
864 this->
skins.push_back(std::move(skinFamily));
867 for (
int i = 0; i < bodyPartCount; i++) {
868 const auto bodyPartPos = bodyPartOffset + i * (
sizeof(int32_t) * 4);
869 stream.seek_u(bodyPartPos);
871 auto& bodyPart = this->
bodyParts.emplace_back();
874 const auto modelsCount = stream.read<int32_t>();
875 stream.read(bodyPart.base);
876 const auto modelsOffset = stream.read<int32_t>();
878 for (
int j = 0; j < modelsCount; j++) {
879 auto modelPos = modelsOffset + j * (64 +
sizeof(float) +
sizeof(int32_t) * 20);
880 if (!seekAndValidate(stream, bodyPartPos + modelPos)) {
884 auto& model = bodyPart.models.emplace_back();
887 .read(model.name, 64)
889 .read(model.boundingRadius);
891 const auto meshesCount = stream.read<int32_t>();
892 const auto meshesOffset = stream.read<int32_t>();
895 .read(model.verticesCount)
896 .read(model.verticesOffset)
897 .read(model.tangentsOffset);
899 const auto modelAttachmentsCount = stream.read<int32_t>();
900 const auto modelAttachmentsOffset = stream.read<int32_t>();
902 const auto eyeballsCount = stream.read<int32_t>();
903 const auto eyeballsOffset = stream.read<int32_t>();
905 for (
int k = 0; k < meshesCount; k++) {
906 const auto meshPos = meshesOffset + k * (
sizeof(int32_t) * (18 +
MAX_LOD_COUNT) +
sizeof(math::Vec3f));
907 if (!seekAndValidate(stream, bodyPartPos + modelPos + meshPos)) {
911 auto& mesh = model.meshes.emplace_back();
916 .read(mesh.verticesCount)
917 .read(mesh.verticesOffset);
919 const auto meshFlexCount = stream.read<int32_t>();
920 const auto meshFlexOffset = stream.read<int32_t>();
923 .read(mesh.materialType)
924 .read(mesh.materialParam)
927 .read(mesh.modelVertexData)
928 .read(mesh.numLODVertexes);
930 stream.skip<int32_t>(8);
932 if (meshFlexOffset != 0) {
934 for (
int m = 0; m < meshFlexCount; m++) {
935 const auto flexPos = meshFlexOffset + m * (
sizeof(int32_t) * 10 +
sizeof(float) * 4 +
sizeof(uint8_t) * 4);
936 if (!seekAndValidate(stream, bodyPartPos + modelPos + meshPos + flexPos)) {
940 auto& flex = mesh.flexes.emplace_back();
943 .read(flex.flexDescIndex)
949 const auto numverts = stream.read<int32_t>();
950 const auto vertindex = stream.read<int32_t>();
954 .read(flex.vertAnimType);
956 if (vertindex != 0) {
958 const auto vertAnimPos = bodyPartPos + modelPos + meshPos + flexPos + vertindex;
959 if (!seekAndValidate(stream, vertAnimPos)) {
963 if (flex.vertAnimType == 0) {
965 flex.vertAnims.reserve(numverts);
966 for (
int n = 0; n < numverts; n++) {
967 auto& vertAnim = flex.vertAnims.emplace_back();
969 .read(vertAnim.index)
970 .read(vertAnim.speed)
972 .read(vertAnim.delta)
973 .read(vertAnim.ndelta);
975 }
else if (flex.vertAnimType == 1) {
977 flex.vertAnimsWrinkle.reserve(numverts);
978 for (
int n = 0; n < numverts; n++) {
979 auto& vertAnim = flex.vertAnimsWrinkle.emplace_back();
981 .read(vertAnim.index)
982 .read(vertAnim.speed)
984 .read(vertAnim.delta)
985 .read(vertAnim.ndelta)
986 .read(vertAnim.wrinkleDelta);
994 if (eyeballsOffset != 0) {
995 for (
int k = 0; k < eyeballsCount; k++) {
996 const auto eyeballPos = eyeballsOffset + k * (
sizeof(int32_t) * 24 +
sizeof(float) * 9 +
sizeof(math::Vec3f) * 3 +
sizeof(uint8_t) * 4);
997 if (!seekAndValidate(stream, bodyPartPos + modelPos + eyeballPos)) {
1001 auto& eyeball = model.eyeballs.emplace_back();
1005 stream.skip<int32_t>();
1010 .read(eyeball.zOffset)
1011 .read(eyeball.radius)
1013 .read(eyeball.forward)
1014 .read(eyeball.texture)
1016 .read(eyeball.irisScale)
1018 .read(eyeball.upperFlexDesc)
1019 .read(eyeball.lowerFlexDesc)
1020 .read(eyeball.upperTarget)
1021 .read(eyeball.lowerTarget)
1022 .read(eyeball.upperLidFlexDesc)
1023 .read(eyeball.lowerLidFlexDesc);
1025 stream.skip<int32_t>(4);
1026 stream.read(eyeball.nonFACS);
1027 stream.skip<uint8_t>(3);
1028 stream.skip<int32_t>(7);
1032 if (modelAttachmentsOffset != 0) {
1033 for (
int k = 0; k < modelAttachmentsCount; k++) {
1034 const auto attachmentPos = modelAttachmentsOffset + k * (
sizeof(int32_t) +
sizeof(uint32_t) +
sizeof(int32_t) +
sizeof(math::Mat3x4f) +
sizeof(int32_t) * 8);
1035 if (!seekAndValidate(stream, bodyPartPos + modelPos + attachmentPos)) {
1039 auto& attachment = model.attachments.emplace_back();
1044 .read(attachment.bone)
1045 .read(attachment.localMatrix);
1048 attachment.position[0] = attachment.localMatrix[0][3];
1049 attachment.position[1] = attachment.localMatrix[1][3];
1050 attachment.position[2] = attachment.localMatrix[2][3];
1052 stream.skip<int32_t>(8);
1058 stream.seek(attachmentOffset);
1059 for (
int i = 0; i < attachmentCount; i++) {
1060 auto& attachment = this->
attachments.emplace_back();
1065 .read(attachment.bone)
1066 .read(attachment.localMatrix);
1069 attachment.position[0] = attachment.localMatrix[0][3];
1070 attachment.position[1] = attachment.localMatrix[1][3];
1071 attachment.position[2] = attachment.localMatrix[2][3];
1073 stream.skip<int32_t>(8);
1076 if (localNodeCount > 0) {
1077 stream.seek(localNodeNameIndex);
1079 for (
int i = 0; i < localNodeCount; i++) {
1085 stream.seek(localNodeIndex);
1086 const auto transitionMatrixSize = localNodeCount * localNodeCount;
1088 for (
int i = 0; i < transitionMatrixSize; i++) {
1093 if (flexDescCount > 0) {
1094 stream.seek(flexDescIndex);
1095 for (
int i = 0; i < flexDescCount; i++) {
1096 auto& flexDescName = this->
flexDescs.emplace_back();
1101 for (
int i = 0; i < flexControllerCount; i++) {
1102 const auto flexControllerPos = flexControllerIndex + i * (
sizeof(int32_t) * 3 +
sizeof(float) * 2);
1103 stream.seek_u(flexControllerPos);
1108 auto readStringAtRelativeOffset = [&](std::string& target) {
1109 if (
const auto offset = stream.read<int32_t>(); offset != 0) {
1110 const auto savedPos = stream.tell();
1112 if (!seekAndValidate(stream, flexControllerPos + offset)) {
1115 stream.read(target);
1116 stream.seek_u(savedPos);
1120 readStringAtRelativeOffset(flexController.type);
1121 readStringAtRelativeOffset(flexController.name);
1124 .read(flexController.localToGlobal)
1125 .read(flexController.min)
1126 .read(flexController.max);
1129 for (
int i = 0; i < flexRulesCount; i++) {
1130 const auto flexRulePos = flexRulesIndex + i * (
sizeof(int32_t) * 3);
1131 stream.seek_u(flexRulePos);
1133 auto& flexRule = this->
flexRules.emplace_back();
1134 stream.read(flexRule.flex);
1136 const auto opCount = stream.read<int32_t>();
1137 const auto opIndex = stream.read<int32_t>();
1139 const auto opDataPos = flexRulePos + opIndex;
1140 stream.seek_u(opDataPos);
1142 for (
int j = 0; j < opCount; j++) {
1143 auto& op = flexRule.ops.emplace_back();
1150 for (
int i = 0; i < ikChainCount; i++) {
1151 const auto ikChainPos = ikChainIndex + i * (
sizeof(int32_t) * 4);
1152 stream.seek_u(ikChainPos);
1154 auto& ikChain = this->
ikChains.emplace_back();
1156 stream.read(ikChain.linkType);
1158 const auto linkCount = stream.read<int32_t>();
1159 const auto linkIndex = stream.read<int32_t>();
1161 const auto linkDataPos = ikChainPos + linkIndex;
1162 stream.seek_u(linkDataPos);
1164 for (
int j = 0; j < linkCount; j++) {
1165 auto& link = ikChain.links.emplace_back();
1169 .skip<math::Vec3f>();
1173 if (mouthsCount > 0) {
1174 stream.seek(mouthsIndex);
1175 for (
int i = 0; i < mouthsCount; i++) {
1176 auto& mouth = this->
mouths.emplace_back();
1179 .read(mouth.forward)
1180 .read(mouth.flexDescIndex);
1184 if (localPoseParamCount > 0) {
1185 stream.seek(localPoseParamIndex);
1187 for (
int i = 0; i < localPoseParamCount; i++) {
1191 .read(poseParam.flags)
1192 .read(poseParam.start)
1193 .read(poseParam.end)
1194 .read(poseParam.loop);
1198 if (surfacePropertyIndex != 0) {
1202 if (keyValueCount > 0) {
1203 stream.seek(keyValueIndex).read(this->
keyValues, keyValueCount);
1206 if (localIKAutoplayLockCount > 0) {
1207 stream.seek(localIKAutoplayLockIndex);
1208 for (
int i = 0; i < localIKAutoplayLockCount; i++) {
1212 .read(ikLock.posWeight)
1213 .read(ikLock.localQWeight)
1214 .read(ikLock.flags);
1215 stream.skip<int32_t>(4);
1219 for (
int i = 0; i < includeModelCount; i++) {
1220 const auto includeModelPos = includeModelIndex + i * (
sizeof(int32_t) * 2);
1221 stream.seek_u(includeModelPos);
1225 auto readStringAtRelativeOffset = [&](std::string& target) {
1226 if (
const auto offset = stream.read<int32_t>(); offset != 0) {
1227 const auto savedPos = stream.tell();
1229 if (!seekAndValidate(stream, includeModelPos + offset)) {
1232 stream.read(target);
1233 stream.seek_u(savedPos);
1237 readStringAtRelativeOffset(includeModel.label);
1238 readStringAtRelativeOffset(includeModel.name);
1241 if (animationBlocksNameIndex != 0) {
1245 if (animationBlocksCount > 0) {
1246 stream.seek(animationBlocksIndex);
1247 for (
int i = 0; i < animationBlocksCount; i++) {
1250 .read(animBlock.dataStart)
1251 .read(animBlock.dataEnd);
1255 if (boneTableNameIndex != 0) {
1256 stream.seek(boneTableNameIndex);
1258 for (
int i = 0; i < boneCount; i++) {
1263 for (
int i = 0; i < flexControllerUICount; i++) {
1264 const auto flexControllerUIPos = flexControllerUIIndex + i * (
sizeof(int32_t) * 4 +
sizeof(uint8_t) * 4);
1265 stream.seek_u(flexControllerUIPos);
1270 const auto szIndex0 = stream.read<int32_t>();
1271 const auto szIndex1 = stream.read<int32_t>();
1272 const auto szIndex2 = stream.read<int32_t>();
1275 .read(flexControllerUI.remapType)
1276 .read(flexControllerUI.stereo);
1278 stream.skip<uint8_t>(2);
1281 auto resolveControllerName = [&](int32_t szIndex, std::string& targetName) {
1283 const auto savedPos = stream.tell();
1284 stream.seek_u(flexControllerUIPos + szIndex);
1285 stream.skip<int32_t>();
1286 if (
const auto controllerNameOffset = stream.read<int32_t>(); controllerNameOffset != 0) {
1288 if (!seekAndValidate(stream, flexControllerUIPos + szIndex + controllerNameOffset)) {
1291 stream.read(targetName);
1293 stream.seek_u(savedPos);
1297 resolveControllerName(szIndex0, flexControllerUI.controllerName0);
1298 resolveControllerName(szIndex1, flexControllerUI.controllerName1);
1299 resolveControllerName(szIndex2, flexControllerUI.controllerName2);