游戏引擎 Mesh相关的代码


struct mesh_head_t
{
    char        common_tag[8];
    char        module_tag[8];
    __int32        version;
    char        description[64];
    byte4       filemask;            
    byte4       length;        
    byte4       materail_offset;        
    byte4       animation_offset;        
    byte4       reserved[10];    
    byte4       mesh_count;            
    byte4        vertex_count;        
    byte4        face_count;            
    byte4        subset_count;            
    byte4        pos_offset;        
    byte4        normal_offset;        
    byte4        color1_offset;        
    byte4        tex1_offset;    
    byte4        tex2_offset;    
    byte4        tex3_offset;    
    byte4        index_buffer_offset;    
    byte4        attri_buffer_offset;    
    byte4        skin_info_offset;        
    byte4        lod_info_offset;        
    byte4        reserved_ex[20];    
};

void mesh_media_t::process()
{
    if(!filedata)
        return;

    mesh_head_t* head = (mesh_head_t*)filedata->GetBufferPointer();
    if( head->filemask != 0x4D455348 )
    {
        clear();
        return;
    }
    if( !head->pos_offset || !head->tex1_offset || !head->index_buffer_offset )
    {
        clear();
        return;
    }

    skin_info = new mesh_skin_info_t;
    skin_info->d3dsi = 0;

    //non-skinned mesh
    if( !head->skin_info_offset )
        return;

    //skinned mesh
    byte* ptr = (byte*)filedata->GetBufferPointer() + head->skin_info_offset;

    skin_info->bone_vec.resize(*(byte4*)ptr);
    ptr += 4;

    if( !skin_info->bone_vec.empty() )
    {
        //create d3dx skin info (may be larger than needed)
        if(FAILED(D3DXCreateSkinInfoFVF(head->vertex_count, D3DFVF_XYZ|D3DFVF_TEX1, (byte4)skin_info->bone_vec.size(), &skin_info->d3dsi)))
        {
            SAFE_DELETE(skin_info);
            clear();
            return;
        }
    }

    for( byte4 i = 0; i < skin_info->bone_vec.size(); i++ )
    {
        strcpy(skin_info->bone_vec[i].name, (char*)ptr);
        ptr += 30;

        skin_info->bone_vec[i].parent_name = (char*)ptr;
        ptr += 30;

        byte4 num_child = *(byte4*)ptr;
        ptr += 4 + num_child * 30;

        skin_info->bone_vec[i].offset_matrix = *(matrix*)ptr;
        ptr += 2 * sizeof(matrix);

        byte4 num_infl = *(byte4*)ptr;
        ptr += 4;
        if( num_infl > 0 )
        {
            skin_info->real_bone_index_vec.push_back(i);
            skin_info->d3dsi->SetBoneInfluence((byte4)skin_info->real_bone_index_vec.size() - 1, num_infl, (byte4*)ptr, (float*)(ptr + 4 * num_infl));
            ptr += num_infl * (sizeof(byte4) + sizeof(float));
        }
    }

    if( skin_info->real_bone_index_vec.empty() )
    {
        //non-skinned in fact
        SAFE_RELEASE(skin_info->d3dsi);
    }

    //compute derived bone members
    //parent index
    for( byte4 i = 0; i < skin_info->bone_vec.size(); i++ )
    {
        skin_info->bone_vec[i].parent_index = -1;

        for( byte4 j = 0; j < skin_info->bone_vec.size(); j++ )
        {
            if( strcmp(skin_info->bone_vec[i].parent_name.c_str(), skin_info->bone_vec[j].name) == 0 )
            {
                skin_info->bone_vec[i].parent_index = j;
                skin_info->bone_vec[i].parent_name.clear();
                break;
            }
        }
    }

    //soft type
    for( byte4 i = 0; i < skin_info->bone_vec.size(); i++ )
    {
        if( strncmp(skin_info->bone_vec[i].name, "FL_", 3) == 0 )
            skin_info->bone_vec[i].soft_type = _bone_soft_type_soft_;
        else if( strncmp(skin_info->bone_vec[i].name, "GL_", 3) == 0 )
            skin_info->bone_vec[i].soft_type = _bone_soft_type_gravity_;
        else if( strncmp(skin_info->bone_vec[i].name, "AL_", 3) == 0)
            skin_info->bone_vec[i].soft_type = _bone_soft_type_adjsoft_;
        else 
            skin_info->bone_vec[i].soft_type = _bone_soft_type_normal_;
    }

    //soft level
    for( byte4 i = 0; i < skin_info->bone_vec.size(); i++ )
        skin_info->bone_vec[i].soft_level = -1;
    for( byte4 i = 0; i < skin_info->bone_vec.size(); i++ )
        _compute_bone_soft_level_recursive(skin_info, i);

    //inv-offset matrix & relative matrix
    for( byte4 i = 0; i < skin_info->bone_vec.size(); i++ )
    {
        D3DXMatrixInverse(&skin_info->bone_vec[i].inv_offset_matrix, 0, &skin_info->bone_vec[i].offset_matrix);
        if( skin_info->bone_vec[i].parent_index != -1 )
            skin_info->bone_vec[i].relative_matrix = skin_info->bone_vec[i].inv_offset_matrix * skin_info->bone_vec[skin_info->bone_vec[i].parent_index].offset_matrix;
        else
            skin_info->bone_vec[i].relative_matrix = skin_info->bone_vec[i].inv_offset_matrix;
    }
    //end of computing derived bone members

    //sockets
    skin_info->socket_vec.resize(*(byte4*)ptr);
    ptr += 4;

    for( byte4 i = 0; i < skin_info->socket_vec.size(); i++ )
    {
        strcpy( skin_info->socket_vec[i].name, (char*)ptr );
        ptr += 30;

        skin_info->socket_vec[i].parent_bone_name = (char*)ptr;
        ptr += 30;

        skin_info->socket_vec[i].relative_matrix = *(matrix*)ptr;
        ptr += sizeof(matrix);
    }

    //compute derived socket members
    for( byte4 i = 0; i < skin_info->socket_vec.size(); i++ )
    {
        skin_info->socket_vec[i].parent_bone_index = -1;

        for( byte4 j = 0; j < skin_info->bone_vec.size(); j++ )
        {
            if( strcmp(skin_info->socket_vec[i].parent_bone_name.c_str(), skin_info->bone_vec[j].name) == 0 )
            {
                skin_info->socket_vec[i].parent_bone_index = j;
                skin_info->socket_vec[i].parent_bone_name.clear();
                break;
            }
        }
    }
    //end of computing derived socket members
}

void mesh_media_t::produce()
{
    if( !filedata || !skin_info )
        return;

    mesh_head_t* head = (mesh_head_t*)filedata->GetBufferPointer();

    //create the original mesh 
    byte4 mesh_option = 0;
    if( !skin_info->d3dsi && gpu()->get_creation_parameters()->vertex_processing_method != _gpu_vertex_processing_method_software_ )
        mesh_option |= D3DXMESH_MANAGED;        //non-skinned && non-soft-vp
    else 
        mesh_option |= D3DXMESH_SYSTEMMEM;    //skinned or soft-vp

    if( head->vertex_count > 0x0000ffff )
        mesh_option |= D3DXMESH_32BIT;

    LPD3DXMESH d3dmesh = 0; 
    if(FAILED(D3DXCreateMeshFVF(head->face_count, head->vertex_count, mesh_option, D3DFVF_XYZ|D3DFVF_TEX1, gpu()->d3ddevice(), &d3dmesh)))
    {
        clear();
        return;
    }

    //load data
    //vertex buffer
    float3* v = (float3*)((byte*)filedata->GetBufferPointer() + head->pos_offset);
    float3* uv = (float3*)((byte*)filedata->GetBufferPointer() + head->tex1_offset);
    xyz_uv_t* vb_v = 0;
    d3dmesh->LockVertexBuffer(0, (void**)&vb_v);
    for( byte4 i = 0; i < head->vertex_count; i++ )
    {
        vb_v[i].xyz = v[i];
        vb_v[i].uv.x = uv[i].x;
        vb_v[i].uv.y = uv[i].y;
    }
    d3dmesh->UnlockVertexBuffer();

    //index buffer
    byte4* f = (byte4*)((byte*)filedata->GetBufferPointer() + head->index_buffer_offset);
    void* ib_f;
    d3dmesh->LockIndexBuffer(0, (void**)&ib_f);
    if( mesh_option & D3DXMESH_32BIT )
        memcpy(ib_f, f, head->face_count * 3 * 4);
    else
    {
        for( byte4 i = 0; i < head->face_count * 3; i++ )
        {
            ((byte2*)ib_f)[i] = (byte2)f[i];
        }
    }
    d3dmesh->UnlockIndexBuffer();

    //attribute buffer
    byte4* ab_ss = 0;
    d3dmesh->LockAttributeBuffer(0, (byte4**)&ab_ss);
    if( !head->attri_buffer_offset )
    {
        memset(ab_ss, 0, head->face_count * 4);
    }
    else
    {
        byte4* ss = (byte4*)((byte*)filedata->GetBufferPointer() + head->attri_buffer_offset);
        memcpy(ab_ss, ss, head->face_count * 4);
    }
    d3dmesh->UnlockAttributeBuffer();
    //end of creating original mesh

    //generate geo info
    geo_info = new mesh_geo_info_t;

    //clear ptrs
    geo_info->vb = 0;
    geo_info->ib = 0;
    geo_info->decl = 0;
    geo_info->attri_table_buf = 0;

    if( !skin_info->d3dsi )    //non-skinned
    {
        //optimize & generate the attribute table
        byte4* adj = new byte4[head->face_count * 3];
        d3dmesh->GenerateAdjacency(0, adj);
        d3dmesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT|D3DXMESHOPT_VERTEXCACHE, adj, 0, 0, 0);
        SAFE_DELETE_ARRAY(adj);

        //retrieve datas (decl is unused and left as 0) (infl_count_vec is unused and left as empty)
        d3dmesh->GetVertexBuffer(&geo_info->vb);
        geo_info->stride = d3dmesh->GetNumBytesPerVertex();
        d3dmesh->GetIndexBuffer(&geo_info->ib);
        geo_info->fvf = d3dmesh->GetFVF();    
        d3dmesh->GetAttributeTable(0, &geo_info->subset_count);
        D3DXCreateBuffer(geo_info->subset_count * sizeof(D3DXATTRIBUTERANGE), &geo_info->attri_table_buf);
        d3dmesh->GetAttributeTable((D3DXATTRIBUTERANGE*)geo_info->attri_table_buf->GetBufferPointer(), &geo_info->subset_count);
        geo_info->palette_count = 0;
        geo_info->max_infl_count = 0;
    }
    else    //skinned
    {
        //generate adjacency
        byte4* adj = new byte4[head->face_count * 3];
        d3dmesh->GenerateAdjacency(0, adj);

        //generate blended mesh
        LPD3DXMESH blended_mesh = 0;
        if( primary_skinning_method == _skinning_method_nonindexed_ || skin_info->real_bone_index_vec.size() == 1 )    //non-indexed
        {
            //pal count
            geo_info->palette_count = 0;

            byte4 flags = D3DXMESHOPT_VERTEXCACHE;
            if( gpu()->get_creation_parameters()->vertex_processing_method == _gpu_vertex_processing_method_software_ )
                flags |= D3DXMESH_SYSTEMMEM;
            else
                flags |= D3DXMESH_MANAGED;

            //convert
            if( FAILED(skin_info->d3dsi->ConvertToBlendedMesh(    d3dmesh, 
                                                                flags,
                                                                adj,
                                                                0, 0, 0,
                                                                (byte4*)&geo_info->max_infl_count,
                                                                (byte4*)&geo_info->subset_count,
                                                                &geo_info->attri_table_buf,
                                                                &blended_mesh )) || 
                (geo_info->max_infl_count > 4) )
            {
                SAFE_DELETE_ARRAY(adj);
                SAFE_DELETE(geo_info);
                SAFE_RELEASE(d3dmesh);
                clear();
                return;
            }

            if( (flags & D3DXMESH_MANAGED) && (geo_info->max_infl_count > max(1, gpu()->get_hardware_caps()->max_matrix_blend_count)) )
            {
                LPD3DXMESH mesh_tmp = 0;
                blended_mesh->CloneMeshFVF( D3DXMESH_SOFTWAREPROCESSING | blended_mesh->GetOptions(), 
                                            blended_mesh->GetFVF(), 
                                            gpu()->d3ddevice(), &mesh_tmp );
                blended_mesh->Release();
                blended_mesh = mesh_tmp;
                mesh_tmp = 0;
            }

            //infl vec
            LPD3DXBONECOMBINATION attr_table = (LPD3DXBONECOMBINATION)(geo_info->attri_table_buf->GetBufferPointer());
            geo_info->infl_count_vec.resize(geo_info->subset_count);
            for( byte4 i = 0; i < geo_info->subset_count; i++ )
            {
                geo_info->infl_count_vec[i] = 0;
                for( byte4 j = 0; j < geo_info->max_infl_count; j++ )
                {
                    if( attr_table[i].BoneId[j] != -1 )
                    {
                        geo_info->infl_count_vec[i] = j + 1;
                    }
                }
            }
        }
        else    //indexed
        {
            //pal count
            geo_info->palette_count = min((byte4)skin_info->real_bone_index_vec.size(), indexed_skinning_max_pal_count);

            byte4 flags = D3DXMESHOPT_VERTEXCACHE;
            switch( gpu()->get_creation_parameters()->vertex_processing_method )
            {
            case _gpu_vertex_processing_method_software_:
            case _gpu_vertex_processing_method_mixed_:
                flags |= D3DXMESH_SYSTEMMEM;    //if the hardware indexed skinning is avaiable, we won't use mixed or software vertex processing method
                break;
            default:
                flags |= D3DXMESH_MANAGED;                
            }

            //convert
            if( FAILED(skin_info->d3dsi->ConvertToIndexedBlendedMesh(    d3dmesh,
                                                                        flags,
                                                                        geo_info->palette_count, 
                                                                          adj, 
                                                                          0, 0, 0, 
                                                                          (byte4*)&geo_info->max_infl_count,
                                                                          (byte4*)&geo_info->subset_count,
                                                                          &geo_info->attri_table_buf,
                                                                          &blended_mesh )) ||
                geo_info->max_infl_count > 4 )
            {
                SAFE_DELETE_ARRAY(adj);
                SAFE_DELETE(geo_info);
                SAFE_RELEASE(d3dmesh);
                clear();
                return;
            }
        }

        //retrieve datas
        blended_mesh->GetVertexBuffer(&geo_info->vb);
        geo_info->stride = blended_mesh->GetNumBytesPerVertex();
        blended_mesh->GetIndexBuffer(&geo_info->ib);

        //fvf
        geo_info->fvf = blended_mesh->GetFVF();

        //decl will be generated later

        SAFE_DELETE_ARRAY(adj);
        SAFE_RELEASE(blended_mesh);
    }

    SAFE_RELEASE(d3dmesh);
    SAFE_RELEASE(skin_info->d3dsi);
    SAFE_RELEASE(filedata);
}

void mesh_media_t::postprocess()
{
    if( !geo_info )
        return;

    if( !geo_info->max_infl_count )
        return;

    if( !geo_info->palette_count )
        return;

    if(    ( primary_skinning_method == _skinning_method_indexed_vs_ ) ||
        ( primary_skinning_method == _skinning_method_indexed_ff_ &&  geo_info->max_infl_count == 1 &&
          ( gpu()->get_creation_parameters()->vertex_processing_method == _gpu_vertex_processing_method_software_ || 
            gpu()->get_creation_parameters()->vertex_processing_method == _gpu_vertex_processing_method_mixed_ )))
    {
        byte4 fvf = geo_info->fvf;
        if( fvf & D3DFVF_LASTBETA_UBYTE4 )    //conpensate for the lack of UBYTE4 on Geforce3
        {
            fvf &= ~D3DFVF_LASTBETA_UBYTE4;
            fvf |= D3DFVF_LASTBETA_D3DCOLOR;
        }
        gpu()->create_vertex_declaration(fvf, &geo_info->decl);
        geo_info->fvf = 0;

        if( !geo_info->decl )
        {
            clear();
            return;
        }
    }
}

media_t* create_mesh(const char* filename, void* arg)
{
    return new mesh_media_t(filename);
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值