#include "MeshFile.h" #include "common/Logger.h" #include "common/OgreBase.h" float tex_width = 512.0f; float tex_height = 256.0f; //--------------------------------------------------------------------- MeshFile::MeshFile(const Ogre::String& file): File(file) { } //--------------------------------------------------------------------- MeshFile::MeshFile(File* pFile): File(pFile) { } //--------------------------------------------------------------------- MeshFile::MeshFile(File* pFile, const u32 offset, const u32 length): File(pFile, offset, length) { } //--------------------------------------------------------------------- MeshFile::MeshFile(u8* pBuffer, const u32 offset, const u32 length): File(pBuffer, offset, length) { } //--------------------------------------------------------------------- MeshFile::~MeshFile(void) { } //--------------------------------------------------------------------- Ogre::ColourValue MeshFile::readColor( const u32 offset ) { u8 r( GetU8( offset + 0 ) ) ,g( GetU8( offset + 1 ) ) ,b( GetU8( offset + 2 ) ) ,a( GetU8( offset + 3 ) ); return Ogre::ColourValue( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f ); } //--------------------------------------------------------------------- void MeshFile::readQuad( const u32 offset_to_poly, std::vector& vertexes, float* &pPos, u16* &index, u32 &cur_vertex, Ogre::RGBA* &cur_colour, bool multi_color ) { u8 i1( GetU8( offset_to_poly + 0x00 ) ) ,i2( GetU8( offset_to_poly + 0x01 ) ) ,i3( GetU8( offset_to_poly + 0x02 ) ) ,i4( GetU8( offset_to_poly + 0x03 ) ); // set vertexes Ogre::Vector3 a( vertexes[ i1 ] ); Ogre::Vector3 b( vertexes[ i2 ] ); Ogre::Vector3 c( vertexes[ i3 ] ); Ogre::Vector3 d( vertexes[ i4 ] ); *pPos++ = a.x; *pPos++ = a.y; *pPos++ = a.z; *pPos++ = b.x; *pPos++ = b.y; *pPos++ = b.z; *pPos++ = c.x; *pPos++ = c.y; *pPos++ = c.z; *pPos++ = d.x; *pPos++ = d.y; *pPos++ = d.z; Ogre::ColourValue col_a = readColor( offset_to_poly + 0x04); Ogre::ColourValue col_b = col_a; Ogre::ColourValue col_c = col_a; Ogre::ColourValue col_d = col_a; if( multi_color ){ col_b = readColor( offset_to_poly + 0x08 ); col_c = readColor( offset_to_poly + 0x0c ); col_d = readColor( offset_to_poly + 0x10 ); }; Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem(); rs->convertColourValue( col_a, cur_colour++ ); rs->convertColourValue( col_b, cur_colour++ ); rs->convertColourValue( col_c, cur_colour++ ); rs->convertColourValue( col_d, cur_colour++ ); *(index++) = cur_vertex + 0; *(index++) = cur_vertex + 2; *(index++) = cur_vertex + 3; *(index++) = cur_vertex + 3; *(index++) = cur_vertex + 1; *(index++) = cur_vertex + 0; cur_vertex += 4; } //--------------------------------------------------------------------- void MeshFile::readTriangle( const u32 offset_to_poly, std::vector& vertexes, float* &pPos, u16* &index, u32 &cur_vertex, Ogre::RGBA* &cur_colour, bool multi_color ) { u8 i1( GetU8( offset_to_poly + 0x00 ) ) ,i2( GetU8( offset_to_poly + 0x01 ) ) ,i3( GetU8( offset_to_poly + 0x02 ) ); // set vertexes Ogre::Vector3 a = vertexes[ i1 ]; Ogre::Vector3 b = vertexes[ i2 ]; Ogre::Vector3 c = vertexes[ i3 ]; *pPos++ = a.x; *pPos++ = a.y; *pPos++ = a.z; *pPos++ = b.x; *pPos++ = b.y; *pPos++ = b.z; *pPos++ = c.x; *pPos++ = c.y; *pPos++ = c.z; Ogre::ColourValue col_a = readColor( offset_to_poly + 0x04 ); Ogre::ColourValue col_b = col_a; Ogre::ColourValue col_c = col_a; if( multi_color ){ col_b = readColor( offset_to_poly + 0x08); col_c = readColor( offset_to_poly + 0x0c); }; Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem(); rs->convertColourValue( col_a, cur_colour++ ); rs->convertColourValue( col_b, cur_colour++ ); rs->convertColourValue( col_c, cur_colour++ ); *(index++) = cur_vertex + 2; *(index++) = cur_vertex + 1; *(index++) = cur_vertex + 0; cur_vertex += 3; } //--------------------------------------------------------------------- void MeshFile::readPart( const Ogre::String& name, const u32 i, const u32 offset_to_part, Ogre::MeshPtr mesh, VectorTexForGenBsx& textures ) { Ogre::String material_name( "ffvii/model/field/" + name ); // add vertexes to array u8 number_of_vertex = GetU8(offset_to_part + 0x02); u16 offset_to_vertexes = GetU16LE(offset_to_part + 0x18); //LOGGER->Log(LOGGER_INFO, "number_of_vertex: %02x", number_of_vertex); std::vector vertexes; for (u32 j = 0; j < number_of_vertex; ++j) { u16 offset_to_vertex = offset_to_vertexes + j * 0x08; Ogre::Vector3 point; point.x = -( s16 )GetU16LE( offset_to_vertex + 4 + 0x00 ); point.z = -( s16 )GetU16LE( offset_to_vertex + 4 + 0x02 ); point.y = -( s16 )GetU16LE( offset_to_vertex + 4 + 0x04 ); point /= 1024.0f; vertexes.push_back( point ); } u8 number_of_quad_t = GetU8(offset_to_part + 0x04); u8 number_of_triangle_t = GetU8(offset_to_part + 0x05); u8 number_of_quad_t2 = GetU8(offset_to_part + 0x06); u8 number_of_triangle_t2 = GetU8(offset_to_part + 0x07); u8 number_of_triangle_m = GetU8(offset_to_part + 0x08); u8 number_of_quad_m = GetU8(offset_to_part + 0x09); u8 number_of_triangle = GetU8(offset_to_part + 0x0A); u8 number_of_quads = GetU8(offset_to_part + 0x0B); size_t quad_count( number_of_quad_t + number_of_quad_t2 + number_of_quad_m + number_of_quads ); size_t triangle_count( number_of_triangle_t + number_of_triangle_t2 + number_of_triangle_m + number_of_triangle ); Ogre::SubMesh* sub_mesh = mesh->createSubMesh(Ogre::StringConverter::toString(i)); sub_mesh->setMaterialName( material_name ); sub_mesh->useSharedVertices = false; sub_mesh->operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; Ogre::HardwareBufferManager& buffer_manager( Ogre::HardwareBufferManager::getSingleton() ); // Allocate and prepare vertex data sub_mesh->vertexData = new Ogre::VertexData(); sub_mesh->vertexData->vertexStart = 0; sub_mesh->vertexData->vertexCount = triangle_count * 3 + quad_count * 4; sub_mesh->indexData = new Ogre::IndexData(); sub_mesh->indexData->indexStart = 0; sub_mesh->indexData->indexCount = triangle_count * 3 + quad_count * 6; sub_mesh->indexData->indexBuffer = buffer_manager.createIndexBuffer( Ogre::HardwareIndexBuffer::IT_16BIT, sub_mesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); u16* cur_index = static_cast< u16* >(sub_mesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD)); u32 cur_vertex = 0; Ogre::VertexDeclaration* decl = sub_mesh->vertexData->vertexDeclaration; Ogre::VertexBufferBinding* bind = sub_mesh->vertexData->vertexBufferBinding; // position buffer decl->addElement(POSITION_BINDING, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); Ogre::HardwareVertexBufferSharedPtr vbuf0 = buffer_manager.createVertexBuffer( decl->getVertexSize(POSITION_BINDING), sub_mesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); bind->setBinding(POSITION_BINDING, vbuf0); // vertex color buffer decl->addElement(COLOUR_BINDING, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); Ogre::HardwareVertexBufferSharedPtr vbuf1 = buffer_manager.createVertexBuffer( decl->getVertexSize(COLOUR_BINDING), sub_mesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); // Set vertex buffer binding so buffer 1 is bound to our colour buffer bind->setBinding(COLOUR_BINDING, vbuf1); // texture coordinate buffer decl->addElement(TEXTURE_BINDING, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0); Ogre::HardwareVertexBufferSharedPtr vbuf2 = buffer_manager.createVertexBuffer( decl->getVertexSize(TEXTURE_BINDING), sub_mesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); bind->setBinding(TEXTURE_BINDING, vbuf2); float* pPos = static_cast(vbuf0->lock(Ogre::HardwareBuffer::HBL_DISCARD)); float* tPos = static_cast(vbuf2->lock(Ogre::HardwareBuffer::HBL_DISCARD)); Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem(); std::vector coloursVec(sub_mesh->vertexData->vertexCount); Ogre::RGBA* colours = coloursVec.data(); Ogre::RGBA* cur_colour( colours ); u32 offset_to_poly = offset_to_vertexes + GetU16LE( offset_to_part + 0x0E ); u32 offset_to_texture_coords = offset_to_vertexes + GetU16LE( offset_to_part + 0x10 ); offset_to_4 = offset_to_vertexes + GetU16LE( offset_to_part + 0x12 ); offset_to_5 = offset_to_vertexes + GetU16LE( offset_to_part + 0x14 ); // add textured quad for( u32 j = 0; j < number_of_quad_t; ++j ) { readQuad( offset_to_poly, vertexes, pPos, cur_index, cur_vertex, cur_colour, true ); TexForGenBsx texture; AddTexture( texture, textures ); Ogre::Vector2 at; Ogre::Vector2 bt; Ogre::Vector2 ct; Ogre::Vector2 dt; u8 texture_coords_id = GetU8( offset_to_poly + 0x14 ); int x = GetU8( offset_to_texture_coords + texture_coords_id * 0x02 + 0x00 ) + texture.start_x; at.x = x / tex_width; int y = GetU8( offset_to_texture_coords + texture_coords_id * 0x02 + 0x01 ) + texture.start_y; at.y = y / tex_height; texture_coords_id = GetU8( offset_to_poly + 0x15 ); x = GetU8( offset_to_texture_coords + texture_coords_id * 0x02 + 0x00 ) + texture.start_x; bt.x = x / tex_width; y = GetU8( offset_to_texture_coords + texture_coords_id * 0x02 + 0x01 ) + texture.start_y; bt.y = y / tex_height; texture_coords_id = GetU8(offset_to_poly + 0x16); x = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x00) + texture.start_x; ct.x = x / tex_width; y = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x01) + texture.start_y; ct.y = y / tex_height; texture_coords_id = GetU8(offset_to_poly + 0x17); x = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x00) + texture.start_x; dt.x = x / tex_width; y = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x01) + texture.start_y; dt.y = y / tex_height; *tPos++ = at.x; *tPos++ = at.y; *tPos++ = bt.x; *tPos++ = bt.y; *tPos++ = ct.x; *tPos++ = ct.y; *tPos++ = dt.x; *tPos++ = dt.y; offset_to_poly += 0x18; } // add textured triangle for (u32 j = 0; j < number_of_triangle_t; ++j) { readTriangle( offset_to_poly, vertexes, pPos, cur_index, cur_vertex, cur_colour, true ); TexForGenBsx texture; AddTexture( texture, textures ); Ogre::Vector2 at; Ogre::Vector2 bt; Ogre::Vector2 ct; u8 texture_coords_id = GetU8(offset_to_poly + 0x10); int x = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x00) + texture.start_x; at.x = x / tex_width; int y = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x01) + texture.start_y; at.y = y / tex_height; texture_coords_id = GetU8(offset_to_poly + 0x11); x = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x00) + texture.start_x; bt.x = x / tex_width; y = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x01) + texture.start_y; bt.y = y / tex_height; texture_coords_id = GetU8(offset_to_poly + 0x12); x = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x00) + texture.start_x; ct.x = x / tex_width; y = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x01) + texture.start_y; ct.y = y / tex_height; *tPos++ = at.x; *tPos++ = at.y; *tPos++ = bt.x; *tPos++ = bt.y; *tPos++ = ct.x; *tPos++ = ct.y; offset_to_poly += 0x14; } // add textured monochrome quad for (u32 j = 0; j < number_of_quad_t2; ++j) { readQuad( offset_to_poly, vertexes, pPos, cur_index, cur_vertex, cur_colour, false ); TexForGenBsx texture; AddTexture( texture, textures ); Ogre::Vector2 at; Ogre::Vector2 bt; Ogre::Vector2 ct; Ogre::Vector2 dt; u8 texture_coords_id = GetU8(offset_to_poly + 0x8); int x = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x00) + texture.start_x; at.x = x / tex_width; int y = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x01) + texture.start_y; at.y = y / tex_height; texture_coords_id = GetU8(offset_to_poly + 0x9); x = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x00) + texture.start_x; bt.x = x / tex_width; y = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x01) + texture.start_y; bt.y = y / tex_height; texture_coords_id = GetU8(offset_to_poly + 0xa); x = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x00) + texture.start_x; dt.x = x / tex_width; y = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x01) + texture.start_y; dt.y = y / tex_height; texture_coords_id = GetU8(offset_to_poly + 0xb); x = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x00) + texture.start_x; ct.x = x / tex_width; y = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x01) + texture.start_y; ct.y = y / tex_height; *tPos++ = at.x; *tPos++ = at.y; *tPos++ = bt.x; *tPos++ = bt.y; *tPos++ = ct.x; *tPos++ = ct.y; *tPos++ = dt.x; *tPos++ = dt.y; offset_to_poly += 0x0C; } // add textured monochrome triangle for (u32 j = 0; j < number_of_triangle_t2; ++j) { readTriangle( offset_to_poly, vertexes, pPos, cur_index, cur_vertex, cur_colour, false ); TexForGenBsx texture; AddTexture( texture, textures ); Ogre::Vector2 at; Ogre::Vector2 bt; Ogre::Vector2 ct; u8 texture_coords_id = GetU8(offset_to_poly + 0x8); int x = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x00) + texture.start_x; at.x = x / tex_width; int y = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x01) + texture.start_y; at.y = y / tex_height; texture_coords_id = GetU8(offset_to_poly + 0x9); x = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x00) + texture.start_x; bt.x = x / tex_width; y = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x01) + texture.start_y; bt.y = y / tex_height; texture_coords_id = GetU8(offset_to_poly + 0xa); x = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x00) + texture.start_x; ct.x = x / tex_width; y = GetU8(offset_to_texture_coords + texture_coords_id * 0x02 + 0x01) + texture.start_y; ct.y = y / tex_height; *tPos++ = at.x; *tPos++ = at.y; *tPos++ = bt.x; *tPos++ = bt.y; *tPos++ = ct.x; *tPos++ = ct.y; offset_to_poly += 0x0C; } // add monochrome triangle for (u32 j = 0; j < number_of_triangle_m; ++j) { readTriangle( offset_to_poly, vertexes, pPos, cur_index, cur_vertex, cur_colour, false ); Ogre::Vector2 at(0.99, 0.99); Ogre::Vector2 bt(0.99, 0.99); Ogre::Vector2 ct(0.99, 0.99); *tPos++ = at.x; *tPos++ = at.y; *tPos++ = bt.x; *tPos++ = bt.y; *tPos++ = ct.x; *tPos++ = ct.y; offset_to_poly += 0x08; } // add monochrome quad for (u32 j = 0; j < number_of_quad_m; ++j) { readQuad( offset_to_poly, vertexes, pPos, cur_index, cur_vertex, cur_colour, false ); Ogre::Vector2 at(0.99, 0.99); Ogre::Vector2 bt(0.99, 0.99); Ogre::Vector2 ct(0.99, 0.99); Ogre::Vector2 dt(0.99, 0.99); *tPos++ = at.x; *tPos++ = at.y; *tPos++ = bt.x; *tPos++ = bt.y; *tPos++ = ct.x; *tPos++ = ct.y; *tPos++ = dt.x; *tPos++ = dt.y; offset_to_poly += 0x08; } // add color triangle for (u32 j = 0; j < number_of_triangle; ++j) { readTriangle( offset_to_poly, vertexes, pPos, cur_index, cur_vertex, cur_colour, true ); Ogre::Vector2 at(0.99, 0.99); Ogre::Vector2 bt(0.99, 0.99); Ogre::Vector2 ct(0.99, 0.99); *tPos++ = at.x; *tPos++ = at.y; *tPos++ = bt.x; *tPos++ = bt.y; *tPos++ = ct.x; *tPos++ = ct.y; offset_to_poly += 0x10; } // add color quad for (u32 j = 0; j < number_of_quads; ++j) { readQuad( offset_to_poly, vertexes, pPos, cur_index, cur_vertex, cur_colour, true ); Ogre::Vector2 a(0.99, 0.99); Ogre::Vector2 b(0.99, 0.99); Ogre::Vector2 c(0.99, 0.99); Ogre::Vector2 d(0.99, 0.99); *tPos++ = a.x; *tPos++ = a.y; *tPos++ = b.x; *tPos++ = b.y; *tPos++ = c.x; *tPos++ = c.y; *tPos++ = d.x; *tPos++ = d.y; offset_to_poly += 0x14; } vbuf0->unlock(); vbuf1->writeData(0, vbuf1->getSizeInBytes(), colours, true); vbuf2->unlock(); sub_mesh->indexData->indexBuffer->unlock(); // Optimize index data sub_mesh->indexData->optimiseVertexCacheTriList(); int vertex_number = sub_mesh->vertexData->vertexCount; u8 bone_index( GetU8(offset_to_part + 0x01) ); //LOGGER->Log(LOGGER_INFO, "vertex_number %08x", vertex_number); for (int i = 0; i < vertex_number; ++i) { Ogre::VertexBoneAssignment vba; vba.vertexIndex = i; vba.boneIndex = bone_index * 2 + 2; vba.weight = 1.0f; sub_mesh->addBoneAssignment(vba); } } //--------------------------------------------------------------------- void MeshFile::GetData(const Ogre::String& name, const int offset_to_parts, const int number_of_parts, Ogre::MeshPtr mesh, VectorTexForGenBsx& textures) { int part_end( number_of_parts ); int part_begin = 0; for (u32 i = part_begin; i < number_of_parts && i < part_end; ++i) { u32 offset_to_part = offset_to_parts + i * 0x20; readPart( name, i, offset_to_part, mesh, textures ); } } //--------------------------------------------------------------------- void MeshFile::AddTexture( TexForGenBsx& texture, VectorTexForGenBsx& textures ) { u8 control = GetU8(offset_to_5); //LOGGER->Log(LOGGER_INFO, "quad control: %02x", control); ++offset_to_5; u8 blend = ( control >> 4 ) & 0x3; u8 flag_id = control & 0xf; u32 flag = GetU32LE( offset_to_4 + flag_id * 4 ); int type = flag & 0x3f; int bpp = (flag >> 0x6) & 0x3; int vram_x = ((flag >> 0x8) & 0xf) * 64; int vram_y = ((flag >> 0xc) & 0x1) * 256; int clut_x = ((flag >> 0x10) & 0x3f) * 16; int clut_y = (flag >> 0x16) & 0x1ff; texture.texture_x = vram_x; texture.texture_y = vram_y; texture.palette_x = clut_x; texture.palette_y = clut_y; texture.bpp = ( BPP )bpp; texture.type = type; for( int i = 0; i < textures.size(); i++ ) { if( texture == textures[ i ] ) { texture.start_x = textures[ i ].start_x; texture.start_y = textures[ i ].start_y; return; } } LOGGER->Log( "New Texture: X:0x" + HexToString( texture.texture_x, 4, '0' ) + ", Y:0x" + HexToString( texture.texture_y, 4, '0' ) + ", CLUTX:0x" + HexToString( texture.palette_x, 4, '0' ) + ", CLUTY:0x" + HexToString( texture.palette_y, 4, '0' ) + ", bpp:0x" + HexToString( texture.bpp, 2, '0' ) + ", type:0x" + HexToString( texture.type, 2, '0' ) + "\n" ); texture.start_x = 0; texture.start_y = 0; for (int i = 0; i < textures.size(); i++) { if (texture.start_x <= textures[i].start_x) { texture.start_x = textures[i].start_x + 256; } } textures.push_back( texture ); //LOGGER->Log(LOGGER_INFO, "Startx:0x%04x, Starty:0x%04x", texture.start_x, texture.start_y); } //---------------------------------------------------------------------