#include #include "../../common/Logger.h" #include "BsxFile.h" #include "BcxFile.h" #include "TdbFile.h" #include "AnimationFile.h" #include "MeshFile.h" #include "SkeletonFile.h" BsxFile::BsxFile(const Ogre::String& file): LzsFile(file), m_Vram(Vram::MakeInstance()) { ReadBSXTextureToVram(); } BsxFile::BsxFile(File* pFile): LzsFile(pFile), m_Vram(Vram::MakeInstance()) { ReadBSXTextureToVram(); } BsxFile::BsxFile(File* pFile, const u32 offset, const u32 length): LzsFile(pFile, offset, length), m_Vram(Vram::MakeInstance()) { ReadBSXTextureToVram(); } BsxFile::BsxFile(u8* pBuffer, const u32 offset, const u32 length): LzsFile(pBuffer, offset, length), m_Vram(Vram::MakeInstance()) { ReadBSXTextureToVram(); } BsxFile::~BsxFile() { } Ogre::Entity* BsxFile::GetModel( Ogre::Entity* entity, const s8 character_id, const Unit& unit, const DatModelData dat ) { int start_animation = ( dat.global_model_id > 0 ) ? 3 : 0; u32 offset_to_models_description = GetU32LE( 0x04 ); s32 number_of_models_description = GetU32LE( offset_to_models_description + 0x04 ); if( character_id >= number_of_models_description ) { return NULL; } u32 offset_to_field_model_description = offset_to_models_description + 0x10 + character_id * 0x30; //LOGGER->Log(LOGGER_INFO, "\n\noffset_to_field_model_description: %08x", offset_to_field_model_description); u8 number_of_bones = GetU8(offset_to_field_model_description + 0x17); u8 number_of_parts = GetU8(offset_to_field_model_description + 0x23); u8 number_of_animations = GetU8(offset_to_field_model_description + 0x2f); //LOGGER->Log(LOGGER_INFO, "number of bones %02x", number_of_bones); //LOGGER->Log(LOGGER_INFO, "number of parts %02x", number_of_parts); //LOGGER->Log(LOGGER_INFO, "number of animations %02x", number_of_animations); VectorTexForGenBsx textures; std::vector< s16 > skeleton_length; Ogre::MeshPtr mesh; Ogre::SkeletonPtr skeleton; if (entity == NULL) { mesh = Ogre::MeshManager::getSingleton().create( "export" + unit.name, "General" ); skeleton = Ogre::SkeletonManager::getSingleton().create( "export" + unit.name, "General" ); switch (dat.global_model_id) { case 1: { BcxFile file( "data/field/cloud.bcx" ); file.GetModel(skeleton_length, unit, mesh, skeleton, textures); } break; case 3: { BcxFile file( "data/field/ballet.bcx" ); file.GetModel(skeleton_length, unit, mesh, skeleton, textures); } break; case 4: { BcxFile file( "data/field/tifa.bcx" ); file.GetModel(skeleton_length, unit, mesh, skeleton, textures); } break; case 7: { BcxFile file( "data/field/yufi.bcx" ); file.GetModel(skeleton_length, unit, mesh, skeleton, textures); } break; default: { // mesh u32 offset_to_parts = offset_to_field_model_description + GetU32LE(offset_to_field_model_description + 0x4) + number_of_bones * 4; MeshFile file_m(this); file_m.GetData(unit.name, offset_to_parts, number_of_parts, mesh, textures); // skeleton u32 offset_to_bones = offset_to_field_model_description + GetU16LE(offset_to_field_model_description + 0x4); SkeletonFile file_s(this); file_s.GetData(skeleton_length, offset_to_bones, number_of_bones, skeleton); } } } else { skeleton = Ogre::SkeletonManager::getSingleton().getByName(entity->getSkeleton()->getName()); switch( dat.global_model_id ) { case 1: { BcxFile file( "data/field/cloud.bcx" ); file.GetSkeleton( skeleton_length ); } break; case 3: { BcxFile file( "data/field/ballet.bcx" ); file.GetSkeleton( skeleton_length ); } break; case 4: { BcxFile file( "data/field/tifa.bcx" ); file.GetSkeleton( skeleton_length ); } break; case 7: { BcxFile file( "data/field/yufi.bcx" ); file.GetSkeleton( skeleton_length ); } break; default: { // skeleton u32 offset_to_bones = offset_to_field_model_description + GetU16LE( offset_to_field_model_description + 0x4 ); SkeletonFile file_s( this ); Ogre::SkeletonPtr null_skeleton; null_skeleton.setNull(); file_s.GetData( skeleton_length, offset_to_bones, number_of_bones, null_skeleton ); } } } // animations u32 offset_to_animations = offset_to_field_model_description + GetU16LE(offset_to_field_model_description + 0x4) + number_of_bones * 4 + number_of_parts * 0x20; AnimationFile file( this ); file.GetData( skeleton_length, unit, offset_to_animations, number_of_animations, start_animation, skeleton ); Ogre::SkeletonSerializer skeleton_serializer; skeleton_serializer.exportSkeleton( skeleton.getPointer(), "exported/models/ffvii/field/units/" + unit.name + ".skeleton" ); if( entity == NULL ) { // Update bounds Ogre::AxisAlignedBox aabb( -999, -999, -999, 999, 999, 999 ); mesh->_setBounds( aabb, false ); mesh->_setBoundingSphereRadius( 999 ); mesh->setSkeletonName( "models/ffvii/field/units/" + unit.name + ".skeleton" ); Ogre::MeshSerializer ser; ser.exportMesh( mesh.getPointer(), "exported/models/ffvii/field/units/" + unit.name + ".mesh" ); // create and export textures for model CreateTexture( unit.name, dat.face_id, textures ); Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( "ffvii/model/field/" + unit.name, "General" ); Ogre::Technique* tech = material->getTechnique( 0 ); Ogre::Pass* pass1 = tech->getPass( 0 ); pass1->setVertexColourTracking( Ogre::TVC_AMBIENT ); pass1->setCullingMode( Ogre::CULL_NONE ); Ogre::Pass* pass2 = tech->createPass(); pass2->setCullingMode( Ogre::CULL_NONE ); pass2->setAlphaRejectFunction( Ogre::CMPF_GREATER ); pass2->setAlphaRejectValue( 0 ); Ogre::TextureUnitState* tex = pass2->createTextureUnitState(); /* if( dat.face_id != 0x21 ) { tex->setTextureScroll( 0.0625 * 2, 0 ); } */ tex->setTextureName( "models/ffvii/field/units/" + unit.name + ".png" ); tex->setNumMipmaps( 0 ); tex->setTextureFiltering( Ogre::TFO_NONE ); Ogre::MaterialSerializer mat; mat.exportMaterial( material, "exported/models/ffvii/field/units/" + unit.name + ".material" ); Ogre::SceneManager* scene_manager = Ogre::Root::getSingleton().getSceneManager( "Scene" ); Ogre::Entity* thisEntity = scene_manager->createEntity( unit.name, "models/ffvii/field/units/" + unit.name + ".mesh" ); //thisEntity->setDisplaySkeleton(true); //thisEntity->setDebugDisplayEnabled(true); thisEntity->setVisible( false ); thisEntity->getAnimationState( "Idle" )->setEnabled( true ); thisEntity->getAnimationState( "Idle" )->setLoop( true ); Ogre::SceneNode* thisSceneNode = scene_manager->getRootSceneNode()->createChildSceneNode(); thisSceneNode->setPosition( 0, 0, 0 ); thisSceneNode->roll( Ogre::Radian( Ogre::Degree( 180.0f ) ) ); thisSceneNode->yaw( Ogre::Radian( Ogre::Degree( 120.0f ) ) ); thisSceneNode->pitch( Ogre::Radian( Ogre::Degree( 90.0f ) ) ); thisSceneNode->attachObject( thisEntity ); return thisEntity; } else { entity->refreshAvailableAnimationState(); return NULL; } } void BsxFile::CreateTexture( const Ogre::String& name, const int face_id, const VectorTexForGenBsx& textures ) { int tex_width = 512; int tex_height = 256; Ogre::TexturePtr ptex; Ogre::HardwarePixelBufferSharedPtr buffer; ptex = Ogre::TextureManager::getSingleton().createManual( "DynaTex", "General", Ogre::TEX_TYPE_2D, tex_width, tex_height, 0, Ogre::PF_R8G8B8A8, Ogre::TU_STATIC ); buffer = ptex->getBuffer( 0, 0 ); buffer->lock( Ogre::HardwareBuffer::HBL_DISCARD ); const Ogre::PixelBox& pb = buffer->getCurrentLock(); for( unsigned int i = 0; i < textures.size(); ++i ) { // type 0x0 - eye, type 0x1 - mouth, type 0x2 - normal texture. if( textures[ i ].type == 0 || textures[ i ].type == 1 ) { TdbFile face_texture( "data/field/field.tdb" ); face_texture.CreateTexture( pb, face_id, textures[ i ].start_x, textures[ i ].start_y ); } else if( textures[ i ].type == 2 ) { CreateTextureFromVram( pb, m_Vram.get(), textures[ i ].start_x, textures[ i ].start_y, textures[ i ].palette_x, textures[ i ].palette_y, textures[ i ].texture_x, textures[ i ].texture_y, textures[ i ].bpp, true ); } } Ogre::Image image; image.loadDynamicImage((Ogre::uchar*)pb.data, tex_width, tex_height, Ogre::PF_R8G8B8A8); image.save( "exported/models/ffvii/field/units/" + name + ".png" ); buffer->unlock(); return; } void BsxFile::ReadBSXTextureToVram() { u32 offset_to_models_description = GetU32LE( 0x04 ); u32 offset_to_texture = offset_to_models_description + GetU32LE( offset_to_models_description + 0x08 ); u32 unknown = GetU32LE( offset_to_texture + 0x04 ) & 0xffffff00; //LOGGER->Log(LOGGER_INFO, "WARNING WARNING %04x", unknown); u8 number_of_texture = GetU8( offset_to_texture + 0x04 ); //LOGGER->Log(LOGGER_INFO, "number_of_texture %04x", number_of_texture); if( number_of_texture == 0 ) { return; } for( int i = 0; i < number_of_texture; ++i ) { u16 width = GetU16LE( offset_to_texture + 0x08 + i * 0x0c + 0x00 ) * 2; u16 height = GetU16LE( offset_to_texture + 0x08 + i * 0x0c + 0x02 ); u16 vram_x = GetU16LE( offset_to_texture + 0x08 + i * 0x0c + 0x04 ) * 2; u16 vram_y = GetU16LE( offset_to_texture + 0x08 + i * 0x0c + 0x06 ); u32 start = offset_to_texture + GetU32LE( offset_to_texture + 0x08 + i * 0x0c + 0x08 ); //LOGGER->Log(LOGGER_INFO, "Store BSX texture to vram %04x %04x", vram_x, vram_y); for( int y = 0; y < height; ++y ) { for( int x = 0; x < width; ++x ) { m_Vram->PutU8( vram_x + x, vram_y + y, GetU8( start + y * width + x ) ); } } } }