#include "AnimationExtractor.h" #include "../../common/Logger.h" float ReadBitStream(File* file, const int offset, int &readed_bits, const int bit_to_read, const int real_size) { int ret = 0; for (int i = 0; i < bit_to_read; ++i) { ret <<= 1; // read new bit int byte = file->GetU8(offset + (readed_bits / 8)); //LOGGER->Log(LOGGER_INFO, "ReadBitStream data = %02x readed_bits = %02x", byte, readed_bits); if ((byte >> (7 - (readed_bits & 7))) & 1) { ret |= 1; } readed_bits += 1; } // force the sign bit to extend across the 32-bit boundary. ret <<= (0x20 - bit_to_read); ret >>= (0x20 - bit_to_read); // extend compressed value ret <<= (real_size - bit_to_read); return (float)ret; } float ReadDynamicFrameOffsetBits(File* file, const int offset, int &readed_bits) { int readed_bytes = readed_bits / 8; int bit_in_byte = readed_bits & 7; int data = (file->GetU8(offset + readed_bytes + 0) << 8) | file->GetU8(offset + readed_bytes + 1); //LOGGER->Log(LOGGER_INFO, "ReadDynamicFrameOffsetBits data = %04x (bit_in_byte %02x)", data, bit_in_byte); if ((data & (1 << (15 - bit_in_byte))) != 0) { // 16 bit value data <<= 8; //LOGGER->Log(LOGGER_INFO, "ReadDynamicFrameOffsetBits 16bit = %04x", data); data |= file->GetU8(offset + readed_bytes + 2); //LOGGER->Log(LOGGER_INFO, "ReadDynamicFrameOffsetBits 16bit = %04x", data); data <<= (bit_in_byte + 9); //LOGGER->Log(LOGGER_INFO, "ReadDynamicFrameOffsetBits 16bit = %04x", data); data >>= 0x10; //LOGGER->Log(LOGGER_INFO, "ReadDynamicFrameOffsetBits 16bit = %04x", data); readed_bits += 17; } else { // 7 bit value data <<= (bit_in_byte + 0x11); data >>= 0x19; //LOGGER->Log(LOGGER_INFO, "ReadDynamicFrameOffsetBits 7bit = %d", data); readed_bits += 8; } //LOGGER->Log(LOGGER_INFO, "ReadDynamicFrameOffsetBits = %d", data); return (float)data; } float ReadEncryptedRotationBits(File* file, const int offset, int &readed_bits, const int compression) { int ret = 0; int control_bit = ReadBitStream(file, offset, readed_bits, 1, 1); //LOGGER->Log(LOGGER_INFO, "ReadEncryptedRotationBits control_bit = %x", control_bit); if (control_bit != 0) { control_bit = ReadBitStream(file, offset, readed_bits, 3, 3); control_bit &= 7; //LOGGER->Log(LOGGER_INFO, "ReadEncryptedRotationBits control_bit = %x", control_bit); if (control_bit == 0) { ret = -1.0f; } else if (control_bit == 7) { ret = ReadBitStream(file, offset, readed_bits, 12 - compression, 12); } else { int data = ReadBitStream(file, offset, readed_bits, control_bit, control_bit); //LOGGER->Log(LOGGER_INFO, "ReadEncryptedRotationBits data = %x", data); if (data >= 0) { data += (1 << (control_bit - 1)); } else { data -= (1 << (control_bit - 1)); } ret = data << (compression + 16); ret >>= 16; } } //LOGGER->Log(LOGGER_INFO, "ReadEncryptedRotationBits = %x", ret); return (float)ret; } void AnimationExtractor(File* file, const Ogre::SkeletonPtr& skeleton, const EnemyInfo& info, Skeleton& skeleton_data, bool with_weapon) { float weapon_tx, weapon_ty, weapon_tz, weapon_rx, weapon_ry, weapon_rz = 0; for (int i = 0; i < info.animations.size(); ++i) { if (info.animations[i] == "") { continue; } LOGGER->Log("AnimationExtractor:" + Ogre::StringConverter::toString(i) + " " + info.animations[i] + "\n"); int offset_to_animation = file->GetU32LE(0x0c + i * 0x04); int offset_to_animation_weapon = 0; if (with_weapon) { offset_to_animation_weapon = file->GetU32LE(0x4c + i * 0x04); } int number_of_frames = file->GetU16LE(offset_to_animation + 0x0); int compression = file->GetU8(offset_to_animation + 0x4); int compression_weapon = 0; if (with_weapon) { compression_weapon = file->GetU8(offset_to_animation_weapon + 0x4); } Ogre::Animation* anim = skeleton->createAnimation(info.animations[i], (number_of_frames - 1) / 10.0f); float time = 0; int readed_bits = 0; int readed_bits_weapon = 0; float tx, ty, tz; Ogre::Bone* bone1; Ogre::Bone* bone2; Ogre::NodeAnimationTrack* track1; Ogre::NodeAnimationTrack* track2; Ogre::TransformKeyFrame* frame1; Ogre::TransformKeyFrame* frame2; Ogre::Quaternion rot; Ogre::Matrix3 mat; for (int frame = 0; frame < number_of_frames; ++frame) { if (readed_bits == 0) { tx = ReadBitStream(file, offset_to_animation + 5, readed_bits, 16, 16); ty = ReadBitStream(file, offset_to_animation + 5, readed_bits, 16, 16); tz = ReadBitStream(file, offset_to_animation + 5, readed_bits, 16, 16); // skip first rotation ReadBitStream(file, offset_to_animation + 5, readed_bits, 12 - compression, 12); ReadBitStream(file, offset_to_animation + 5, readed_bits, 12 - compression, 12); ReadBitStream(file, offset_to_animation + 5, readed_bits, 12 - compression, 12); bone1 = skeleton->getBone(0); track1 = anim->createNodeTrack(0, bone1); track1->removeAllKeyFrames(); frame1 = track1->createNodeKeyFrame(time); mat.FromEulerAnglesYXZ(Ogre::Radian(Ogre::Degree(0)), Ogre::Radian(Ogre::Degree(-90)), Ogre::Radian(Ogre::Degree(0))); rot.FromRotationMatrix(mat); frame1->setRotation(rot); bone2 = skeleton->getBone(1); track2 = anim->createNodeTrack(1, bone2); track2->removeAllKeyFrames(); frame2 = track2->createNodeKeyFrame(time); frame2->setTranslate(Ogre::Vector3(tx, ty, tz) / 512); for (int bone = 0; bone < skeleton_data.size(); ++bone) { skeleton_data[bone].rx = (ReadBitStream(file, offset_to_animation + 5, readed_bits, 12 - compression, 12) / 4096.0f) * 360; skeleton_data[bone].ry = (ReadBitStream(file, offset_to_animation + 5, readed_bits, 12 - compression, 12) / 4096.0f) * 360; skeleton_data[bone].rz = (ReadBitStream(file, offset_to_animation + 5, readed_bits, 12 - compression, 12) / 4096.0f) * 360; bone1 = skeleton->getBone(bone * 2 + 2); bone2 = skeleton->getBone(bone * 2 + 3); track1 = anim->createNodeTrack(bone * 2 + 2, bone1); track1->removeAllKeyFrames(); track2 = anim->createNodeTrack(bone * 2 + 3, bone2); track2->removeAllKeyFrames(); frame1 = track1->createNodeKeyFrame(time); frame2 = track2->createNodeKeyFrame(time); frame2->setTranslate(Ogre::Vector3(0, 0, skeleton_data[bone].length) / 512); mat.FromEulerAnglesYXZ(Ogre::Radian(Ogre::Degree(skeleton_data[bone].ry)), Ogre::Radian(Ogre::Degree(skeleton_data[bone].rx)), Ogre::Radian(Ogre::Degree(skeleton_data[bone].rz))); rot.FromRotationMatrix(mat); frame1->setRotation(rot); } if (with_weapon) { weapon_tx = ReadBitStream(file, offset_to_animation_weapon + 5, readed_bits_weapon, 16, 16); weapon_ty = ReadBitStream(file, offset_to_animation_weapon + 5, readed_bits_weapon, 16, 16); weapon_tz = ReadBitStream(file, offset_to_animation_weapon + 5, readed_bits_weapon, 16, 16); weapon_rx = (ReadBitStream(file, offset_to_animation_weapon + 5, readed_bits_weapon, 12 - compression_weapon, 12) / 4096.0f) * 360; weapon_ry = (ReadBitStream(file, offset_to_animation_weapon + 5, readed_bits_weapon, 12 - compression_weapon, 12) / 4096.0f) * 360; weapon_rz = (ReadBitStream(file, offset_to_animation_weapon + 5, readed_bits_weapon, 12 - compression_weapon, 12) / 4096.0f) * 360; bone1 = skeleton->getBone(skeleton_data.size() * 2 + 3); track1 = anim->createNodeTrack(skeleton_data.size() * 2 + 3, bone1); track1->removeAllKeyFrames(); frame1 = track1->createNodeKeyFrame(time); mat.FromEulerAnglesYXZ(Ogre::Radian(Ogre::Degree(weapon_ry)), Ogre::Radian(Ogre::Degree(weapon_rx)), Ogre::Radian(Ogre::Degree(weapon_rz))); rot.FromRotationMatrix(mat); frame1->setRotation(rot); bone2 = skeleton->getBone(skeleton_data.size() * 2 + 2); track2 = anim->createNodeTrack(skeleton_data.size() * 2 + 2, bone2); track2->removeAllKeyFrames(); frame2 = track2->createNodeKeyFrame(time); frame2->setTranslate(Ogre::Vector3(weapon_tx, weapon_ty, weapon_tz) / 512); } } else { tx += ReadDynamicFrameOffsetBits(file, offset_to_animation + 5, readed_bits); ty += ReadDynamicFrameOffsetBits(file, offset_to_animation + 5, readed_bits); tz += ReadDynamicFrameOffsetBits(file, offset_to_animation + 5, readed_bits); // skip first rotation ReadEncryptedRotationBits(file, offset_to_animation + 5, readed_bits, compression); ReadEncryptedRotationBits(file, offset_to_animation + 5, readed_bits, compression); ReadEncryptedRotationBits(file, offset_to_animation + 5, readed_bits, compression); bone1 = skeleton->getBone(0); track1 = anim->getNodeTrack(0); frame1 = track1->createNodeKeyFrame(time); mat.FromEulerAnglesYXZ(Ogre::Radian(Ogre::Degree(0)), Ogre::Radian(Ogre::Degree(-90)), Ogre::Radian(Ogre::Degree(0))); rot.FromRotationMatrix(mat); frame1->setRotation(rot); bone2 = skeleton->getBone(1); track2 = anim->getNodeTrack(1); frame2 = track2->createNodeKeyFrame(time); frame2->setTranslate(Ogre::Vector3(tx, ty, tz) / 512); for (int bone = 0; bone < skeleton_data.size(); ++bone) { skeleton_data[bone].rx += (ReadEncryptedRotationBits(file, offset_to_animation + 5, readed_bits, compression) / 4096.0f) * 360; skeleton_data[bone].ry += (ReadEncryptedRotationBits(file, offset_to_animation + 5, readed_bits, compression) / 4096.0f) * 360; skeleton_data[bone].rz += (ReadEncryptedRotationBits(file, offset_to_animation + 5, readed_bits, compression) / 4096.0f) * 360; bone1 = skeleton->getBone(bone * 2 + 2); bone2 = skeleton->getBone(bone * 2 + 3); track1 = anim->getNodeTrack(bone * 2 + 2); track2 = anim->getNodeTrack(bone * 2 + 3); frame1 = track1->createNodeKeyFrame(time); frame2 = track2->createNodeKeyFrame(time); frame2->setTranslate(Ogre::Vector3(0, 0, skeleton_data[bone].length) / 512); mat.FromEulerAnglesYXZ(Ogre::Radian(Ogre::Degree(skeleton_data[bone].ry)), Ogre::Radian(Ogre::Degree(skeleton_data[bone].rx)), Ogre::Radian(Ogre::Degree(skeleton_data[bone].rz))); rot.FromRotationMatrix(mat); frame1->setRotation(rot); } if (with_weapon) { weapon_tx += ReadDynamicFrameOffsetBits(file, offset_to_animation_weapon + 5, readed_bits_weapon); weapon_ty += ReadDynamicFrameOffsetBits(file, offset_to_animation_weapon + 5, readed_bits_weapon); weapon_tz += ReadDynamicFrameOffsetBits(file, offset_to_animation_weapon + 5, readed_bits_weapon); weapon_rx += (ReadEncryptedRotationBits(file, offset_to_animation_weapon + 5, readed_bits_weapon, compression_weapon) / 4096.0f) * 360; weapon_ry += (ReadEncryptedRotationBits(file, offset_to_animation_weapon + 5, readed_bits_weapon, compression_weapon) / 4096.0f) * 360; weapon_rz += (ReadEncryptedRotationBits(file, offset_to_animation_weapon + 5, readed_bits_weapon, compression_weapon) / 4096.0f) * 360; bone1 = skeleton->getBone(skeleton_data.size() * 2 + 3); track1 = anim->getNodeTrack(skeleton_data.size() * 2 + 3); frame1 = track1->createNodeKeyFrame(time); mat.FromEulerAnglesYXZ(Ogre::Radian(Ogre::Degree(weapon_ry)), Ogre::Radian(Ogre::Degree(weapon_rx)), Ogre::Radian(Ogre::Degree(weapon_rz))); rot.FromRotationMatrix(mat); frame1->setRotation(rot); bone2 = skeleton->getBone(skeleton_data.size() * 2 + 2); track2 = anim->getNodeTrack(skeleton_data.size() * 2 + 2); frame2 = track2->createNodeKeyFrame(time); frame2->setTranslate(Ogre::Vector3(weapon_tx, weapon_ty, weapon_tz) / 512); } } time += 1.0f / 10.0f; } } }