#include"AssimpLoader.h"
#include<assimp/postprocess.h>
#include<assimp/cimport.h>
#include<hgl/filesystem/FileSystem.h>
#include<hgl/type/List.h>
#include<hgl/io/MemoryOutputStream.h>
#include<hgl/graph/TextureType.h>

using namespace hgl;
using namespace hgl::graph;

#define LOG_BR  LOG_INFO(OS_TEXT("------------------------------------------------------------"));

#define aisgl_min(x,y) (x<y?x:y)
#define aisgl_max(x,y) (y>x?y:x)

void set_float4(float f[4], float a, float b, float c, float d)
{
    f[0] = a;
    f[1] = b;
    f[2] = c;
    f[3] = d;
}

void color4_to_float4(const aiColor4D *c, float f[4])
{
    f[0] = c->r;
    f[1] = c->g;
    f[2] = c->b;
    f[3] = c->a;
}

void AssimpLoader::get_bounding_box_for_node (const aiNode* nd,
                                                aiVector3D* min,
                                                aiVector3D* max,
                                                aiMatrix4x4* trafo)
{
    aiMatrix4x4 prev;
    unsigned int n = 0, t;

    prev = *trafo;
    aiMultiplyMatrix4(trafo,&nd->mTransformation);

    for (; n < nd->mNumMeshes; ++n)
    {
        const aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];

        for (t = 0; t < mesh->mNumVertices; ++t)
        {
            aiVector3D tmp = mesh->mVertices[t];
            aiTransformVecByMatrix4(&tmp,trafo);

            min->x = aisgl_min(min->x,tmp.x);
            min->y = aisgl_min(min->y,tmp.y);
            min->z = aisgl_min(min->z,tmp.z);

            max->x = aisgl_max(max->x,tmp.x);
            max->y = aisgl_max(max->y,tmp.y);
            max->z = aisgl_max(max->z,tmp.z);
        }
    }

    for (n = 0; n < nd->mNumChildren; ++n)
        get_bounding_box_for_node(nd->mChildren[n],min,max,trafo);

    *trafo = prev;
}

void AssimpLoader::get_bounding_box (const aiNode *node,aiVector3D* min, aiVector3D* max)
{
    aiMatrix4x4 trafo;

    aiIdentityMatrix4(&trafo);

    min->x = min->y = min->z =  1e10f;
    max->x = max->y = max->z = -1e10f;

    get_bounding_box_for_node(node,min,max,&trafo);
}

AssimpLoader::AssimpLoader()
{
    scene=0;
    material_list=nullptr;
}

AssimpLoader::~AssimpLoader()
{
    delete[] material_list;

    if(scene)
        aiReleaseImport(scene);
}

void AssimpLoader::SaveFile(const void *data,const uint &size,const OSString &ext_name)
{
    if(!data||size<=0)return;

    OSString filename=main_filename+OS_TEXT(".")+ext_name;

    if(filesystem::SaveMemoryToFile(filename,data,size)==size)
    {
        LOG_INFO(OS_TEXT("SaveFile: ")+filename+OS_TEXT(" , size: ")+OSString(size));

        total_file_bytes+=size;
    }
}

void AssimpLoader::SaveFile(void **data,const int64 *size,const int &count,const OSString &ext_name)
{
    if(!data||size<=0)return;

    OSString filename=main_filename+OS_TEXT(".")+ext_name;

    int64 result=filesystem::SaveMemoryToFile(filename,data,size,count);

    if(result>0)
    {
        LOG_INFO(OS_TEXT("SaveFile: ")+filename+OS_TEXT(" , size: ")+OSString(result));

        total_file_bytes+=result;
    }
}

void OutFloat3(const OSString &front,const Color4f &c)
{
    LOG_INFO(front+OS_TEXT(": ")+OSString(c.r)
                  +OS_TEXT("," )+OSString(c.g)
                  +OS_TEXT("," )+OSString(c.b));
}

constexpr VkSamplerAddressMode vk_wrap[4]=              //对应aiTextureMapMode,注意最后一个其实不对
{
    VK_SAMPLER_ADDRESS_MODE_REPEAT,
    VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
    VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
    VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE        //这个是declas
};

void OutMaterialTexture(const MaterialTextureData &mt,io::DataOutputStream *dos)
{
    dos->WriteUint8((uint8)mt.type);
    dos->WriteInt32(mt.tex_id);
    dos->WriteUint8(mt.uvindex);
    dos->WriteFloat(mt.blend);
    dos->WriteUint8(mt.op);
    dos->WriteUint8(mt.wrap_mode,2);

    LOG_INFO(OS_TEXT("\tTexture Type: ")+OSString((uint)mt.type));
    LOG_INFO(OS_TEXT("\tTexture ID: ")+OSString(mt.tex_id));

    LOG_INFO(OS_TEXT("\tuvindex: ")+OSString(mt.uvindex));
    LOG_INFO(OS_TEXT("\tblend: ")+OSString(mt.blend));
    LOG_INFO(OS_TEXT("\top: ")+OSString(mt.op));
    LOG_INFO(OS_TEXT("\twrap_mode: ")+OSString(mt.wrap_mode[0])+OS_TEXT(",")+OSString(mt.wrap_mode[1]));
}

void OutMaterial(const MaterialData *ms,const OSString &filename)
{
    io::FileOutputStream fos;
    io::LEDataOutputStream dos(&fos);

    fos.CreateTrunc(filename);

    dos.WriteFully("Material\x1A\x1",10);
    dos.WriteFloat(ms->diffuse,3);
    dos.WriteFloat(ms->specular,3);
    dos.WriteFloat(ms->ambient,3);
    dos.WriteFloat(ms->emission,3);
    dos.WriteFloat(ms->shininess);
    dos.WriteBool(ms->wireframe);
    dos.WriteBool(ms->two_sided);
    dos.WriteUint8(ms->tex_count);

    OutFloat3(OSString(OS_TEXT("diffuse")),ms->diffuse);
    OutFloat3(OSString(OS_TEXT("specular")),ms->specular);
    OutFloat3(OSString(OS_TEXT("ambient")),ms->ambient);
    OutFloat3(OSString(OS_TEXT("emission")),ms->emission);

    LOG_INFO(OS_TEXT("shininess: ")+OSString(ms->shininess));

    LOG_INFO(OS_TEXT("wireframe: ")+OSString(ms->wireframe?OS_TEXT("true"):OS_TEXT("false")));
    LOG_INFO(OS_TEXT("two_sided: ")+OSString(ms->two_sided?OS_TEXT("true"):OS_TEXT("false")));

    LOG_INFO(OS_TEXT("Material Texture Count ")+OSString(ms->tex_count));

    for(int i=0;i<ms->tex_count;i++)
        OutMaterialTexture(ms->tex_list[i],&dos);

    fos.Close();
}

bool GetMaterialBool(aiMaterial *mtl,const char *key,unsigned int type,unsigned int index,const bool default_value)
{
    int value;

    if(aiGetMaterialInteger(mtl, AI_MATKEY_TWOSIDED, &value)==AI_SUCCESS)
        return value;
    else
        return default_value;
}

uint GetMaterialInteger(aiMaterial *mtl,const char *key,unsigned int type,unsigned int index,const uint default_value)
{
    int value;

    if(aiGetMaterialInteger(mtl, AI_MATKEY_TWOSIDED, &value)==AI_SUCCESS)
        return value;
    else
        return default_value;
}

float GetMaterialFloat(aiMaterial *mtl,const char *key,unsigned int type,unsigned int index,const float default_value)
{
    float value;

    if(aiGetMaterialFloat(mtl, AI_MATKEY_TWOSIDED, &value)==AI_SUCCESS)
        return value;
    else
        return default_value;
}

Color4f GetMaterialColor(aiMaterial *mtl,const char *key,unsigned int type,unsigned int index,const Color4f &default_value)
{
    unsigned int max = 1;
    aiColor4D color;

    if(aiGetMaterialColor(mtl, AI_MATKEY_TWOSIDED, &color)==AI_SUCCESS)
        return Color4f(color.r,color.g,color.b,color.a);
    else
        return default_value;
}

void AssimpLoader::LoadMaterial()
{
    if(!scene->HasMaterials())return;

    int ret1, ret2;
    float c[4];
    aiColor4D diffuse;
    aiColor4D specular;
    aiColor4D ambient;
    aiColor4D emission;
    float shininess;
    float strength;
    float bump_scaling;
    float opacity;
    float refracti;
    aiColor4D transparent;
    aiColor4D reflective;

    int two_sided;
    int wireframe;
    unsigned int max;   // changed: to unsigned

    LOG_BR;
    LOG_INFO(OS_TEXT("Material Count ")+OSString(scene->mNumMaterials));
    LOG_BR;

    aiString filename;
    aiTextureMapping tm;
    uint uvindex=0;
    float blend;
    aiTextureOp op;
    aiTextureMapMode wrap_mode[2];

    material_count=scene->mNumMaterials;

    material_list=new MaterialData[material_count];

    for(unsigned int m=0;m<scene->mNumMaterials;m++)
    {
        int tex_index=0;
        int tex_count=0;
        int tt_count=0;
        int32 tex_id;
        aiReturn found=AI_SUCCESS;

        aiMaterial *mtl=scene->mMaterials[m];

        for(uint tt=aiTextureType_DIFFUSE;tt<aiTextureType_UNKNOWN;tt++)
        {
            tex_count+=mtl->GetTextureCount((aiTextureType)tt);
        }

        MaterialData *ms=&(material_list[m]);

        ms->Init(tex_count);

        for(uint tt=aiTextureType_DIFFUSE;tt<aiTextureType_UNKNOWN;tt++)
        {
            tt_count=mtl->GetTextureCount((aiTextureType)tt);

            for(int t=0;t<tt_count;t++)
            {
                mtl->GetTexture((aiTextureType)tt,t,&filename,&tm,&uvindex,&blend,&op,wrap_mode);

                ms->tex_list[tex_index].type=(TextureType)tt;

                ms->uv_use.Add(uvindex);

                {
                    char *fn=strrchr(filename.data,'\\');
                    char *ext;

                    if(!fn)
                        fn=strrchr(filename.data,'/');
                    else
                        ++fn;

                    if(fn)
                        ++fn;
                    else
                        fn=filename.data;

                    ext=strrchr(fn,'.');

                    if(ext)*ext=0;

                #if HGL_OS == HGL_OS_Window
                    tex_id=tex_list.CaseFind(fn);
                #else
                    tex_id=tex_list.Find(fn);
                #endif//

                    if(tex_id==-1)
                        tex_id=tex_list.Add(fn);

                    ms->tex_list[tex_index].tex_id=tex_id;
                }

                ms->tex_list[tex_index].uvindex=uvindex;
                ms->tex_list[tex_index].blend=blend;
                ms->tex_list[tex_index].op=op;

                ms->tex_list[tex_index].wrap_mode[0]=vk_wrap[wrap_mode[0]];
                ms->tex_list[tex_index].wrap_mode[1]=vk_wrap[wrap_mode[1]];

                ++tex_index;
            }
        }

        ms->two_sided           =GetMaterialBool    (mtl,AI_MATKEY_TWOSIDED,        true);
        ms->shading_model       =GetMaterialInteger (mtl,AI_MATKEY_SHADING_MODEL,   aiShadingMode_Phong);
        ms->wireframe           =GetMaterialBool    (mtl,AI_MATKEY_ENABLE_WIREFRAME,false);
//        ms->blend_func          =
        ms->opacity             =GetMaterialFloat(mtl,AI_MATKEY_OPACITY,            0);
//        ms->transparency_factor =

        ms->bump_scaling        =GetMaterialFloat(mtl,AI_MATKEY_BUMPSCALING,        0);
        ms->shininess           =GetMaterialFloat(mtl,AI_MATKEY_SHININESS,          0);
        ms->shininess_strength  =GetMaterialFloat(mtl,AI_MATKEY_SHININESS_STRENGTH, 0);
        ms->reflectivity        =GetMaterialFloat(mtl,AI_MATKEY_REFLECTIVITY,       0);
        ms->refracti            =GetMaterialFloat(mtl,AI_MATKEY_REFRACTI,           0);

        ms->diffuse             =GetMaterialColor(mtl,AI_MATKEY_COLOR_DIFFUSE,      pure_white_color);
        ms->ambient             =GetMaterialColor(mtl,AI_MATKEY_COLOR_AMBIENT,      Color4f(0.2,0.2,0.2,1.0));
        ms->specular            =GetMaterialColor(mtl,AI_MATKEY_COLOR_SPECULAR,     pure_black_color);
        ms->emission            =GetMaterialColor(mtl,AI_MATKEY_COLOR_EMISSIVE,     pure_black_color);

        ms->transparent         =GetMaterialColor(mtl,AI_MATKEY_COLOR_TRANSPARENT,  pure_black_color);
        ms->reflective          =GetMaterialColor(mtl,AI_MATKEY_COLOR_REFLECTIVE,   pure_black_color);

        OutMaterial(ms,main_filename+OS_TEXT(".")+OSString(m)+OS_TEXT(".material"));
        LOG_BR;
    }
}

void AssimpLoader::SaveTextures()
{
    const int tex_count=tex_list.GetCount();

    LOG_INFO(OS_TEXT("TOTAL Texture Count: ")+OSString(tex_count));

    if(tex_count<=0)
        return;

    for(int i=0;i<tex_count;i++)
        LOG_INFO(U8_TEXT("\t")+UTF8String(i)+U8_TEXT("\t")+tex_list[i]);

    LOG_BR;

    io::MemoryOutputStream mos;
    io::LEDataOutputStream dos(&mos);

    SaveUTF8StringList(&dos,tex_list);

    SaveFile(mos.GetData(),mos.Tell(),OS_TEXT("tex_list"));
}

template<typename T>
void AssimpLoader::SaveFaces(io::FileOutputStream *fos,const aiFace *face,const T count)
{
    T *data=new T[count*3];

    const aiFace *sp=face;
    T *tp=data;

    for(T i=0;i<count;i++)
    {
        *tp=sp->mIndices[0];++tp;
        *tp=sp->mIndices[1];++tp;
        *tp=sp->mIndices[2];++tp;

        ++sp;
    }

    fos->WriteFully(data,sizeof(T)*3*count);

    delete[] data;
}

void AssimpLoader::SaveTexCoord(float *tp,const aiVector3D *texcoord,const uint comp,const uint count)
{
    if(comp<=0||comp>3)
        return;

    const uint size=1+sizeof(float)*comp*count;

    const aiVector3D *sp=texcoord;

    if(comp==1)
    {
        for(uint i=0;i<count;i++)
        {
            *tp=sp->x;++tp;
            ++sp;
        }
    }
    else
    if(comp==2)
    {
        for(uint i=0;i<count;i++)
        {
            *tp=sp->x;++tp;
            *tp=sp->y;++tp;
            ++sp;
        }
    }
    else
    if(comp==3)
    {
        for(uint i=0;i<count;i++)
        {
            *tp=sp->x;++tp;
            *tp=sp->y;++tp;
            *tp=sp->z;++tp;
            ++sp;
        }
    }
}

void c4f_to_4b(uint8 *tp,const aiColor4D *c4,const int count)
{
    for(int i=0;i<count;i++)
    {
        *tp=c4->r*255;++tp;
        *tp=c4->g*255;++tp;
        *tp=c4->b*255;++tp;
        *tp=c4->a*255;++tp;
    }
}

void AxisY2Z(aiVector3D *v,const uint32 count)
{
    ai_real t;

    for(uint32 i=0;i<count;i++)
    {
        t=v->y;
        v->y=-(v->z);
        v->z=t;

        ++v;
    }
}

void AssimpLoader::LoadMesh()
{
    if(!scene->HasMeshes())return;

    UTF8String mesh_name;

    total_file_bytes=0;

    LOG_BR;
    LOG_INFO(OS_TEXT("Mesh Count ")+OSString(scene->mNumMeshes));

    uint vertex_total=0;
    uint tri_total=0;
    uint bone_total=0;

    for(unsigned int i=0;i<scene->mNumMeshes;i++)
    {
        const aiMesh *mesh=scene->mMeshes[i];

        const uint v3fdata_size=mesh->mNumVertices*3*sizeof(float);
        const uint v4fdata_size=mesh->mNumVertices*4*sizeof(float);

        if(mesh->mName.length)
            mesh_name=U8_TEXT("Mesh [")+UTF8String(i)+U8_TEXT(":")+UTF8String(mesh->mName.C_Str())+U8_TEXT("]");
        else
            mesh_name=U8_TEXT("Mesh [")+UTF8String(i)+U8_TEXT("]");

        int pn=mesh->mFaces[0].mNumIndices;

        LOG_BR;

        LOG_INFO(mesh_name+U8_TEXT(" PrimitiveTypes is ")+UTF8String(mesh->mPrimitiveTypes));

        LOG_INFO(mesh_name+U8_TEXT(" vertex color count is ")+UTF8String(mesh->GetNumColorChannels()));
        LOG_INFO(mesh_name+U8_TEXT(" texcoord count is ")+UTF8String(mesh->GetNumUVChannels()));

        if(mesh->GetNumUVChannels()>0)
            LOG_INFO(mesh_name+U8_TEXT(" Material Index is ")+UTF8String(mesh->mMaterialIndex));

        if(mesh->HasPositions())LOG_INFO(mesh_name+U8_TEXT(" have Position, vertices count ")+UTF8String(mesh->mNumVertices));
        if(mesh->HasFaces())LOG_INFO(mesh_name+U8_TEXT(" have Faces,faces count ")+UTF8String(mesh->mNumFaces));
        if(mesh->HasNormals())LOG_INFO(mesh_name+U8_TEXT(" have Normals"));
        if(mesh->HasTangentsAndBitangents())LOG_INFO(mesh_name+U8_TEXT(" have Tangent & Bitangents"));
        if(mesh->HasBones())LOG_INFO(mesh_name+U8_TEXT(" have Bones, Bones Count ")+UTF8String(mesh->mNumBones));

        vertex_total+=mesh->mNumVertices;
        tri_total+=mesh->mNumFaces;
        bone_total+=mesh->mNumBones;

        LOG_INFO(mesh_name+U8_TEXT(" PN is ")+UTF8String(pn));

        if(pn!=3)
            continue;

        MaterialData *mtl=&(material_list[mesh->mMaterialIndex]);

        const uint uv_channels=mtl->uv_use.GetCount();

        LOG_INFO(mesh_name+U8_TEXT(" use UV Channels is ")+UTF8String(uv_channels));

        io::FileOutputStream fos;

        OSString mesh_filename=main_filename+OS_TEXT(".")+OSString(i)+OS_TEXT(".mesh");

        if(!fos.CreateTrunc(mesh_filename))
        {
            LOG_INFO(OS_TEXT("Create Mesh file Failed,filename: ")+mesh_filename);
            continue;
        }

        {
            MeshFileHeader ms;

            ms.primitive_type   =PRIM_TRIANGLES;
            ms.vertices_number  =mesh->mNumVertices;
            ms.faces_number     =mesh->mNumFaces;
            ms.color_channels   =mesh->GetNumColorChannels();
            ms.texcoord_channels=uv_channels;
            ms.material_index   =mesh->mMaterialIndex;

            if(mesh->HasNormals())
            {
                if(mesh->HasTangentsAndBitangents())
                    ms.ntb=NTB_BIT_ALL;
                else
                    ms.ntb=NTB_BIT_NORMAL;
            }

            ms.bones_number     =mesh->mNumBones;

            fos.WriteFully(&ms,sizeof(MeshFileHeader));
        }

        if(mesh->HasPositions())
        {
            AxisY2Z(mesh->mVertices,mesh->mNumVertices);
            fos.WriteFully(mesh->mVertices,v3fdata_size);
        }

        if(mesh->HasNormals())
        {
            AxisY2Z(mesh->mNormals,mesh->mNumVertices);
            fos.WriteFully(mesh->mNormals,v3fdata_size);

            if(mesh->HasTangentsAndBitangents())
            {
                AxisY2Z(mesh->mTangents,mesh->mNumVertices);
                AxisY2Z(mesh->mBitangents,mesh->mNumVertices);

                fos.WriteFully(mesh->mTangents,v3fdata_size);
                fos.WriteFully(mesh->mBitangents,v3fdata_size);
            }
        }

        if(mesh->GetNumColorChannels()>0)
        {
            const int64 vertex_color_size=mesh->mNumVertices*4*mesh->GetNumColorChannels();

            uint8 *vertex_color=new uint8[vertex_color_size];
            uint8 *tp=vertex_color;

            for(int c=0;c<mesh->GetNumColorChannels();c++)
            {
                c4f_to_4b(tp,mesh->mColors[c],mesh->mNumVertices);
                tp+=mesh->mNumVertices*4;
            }

            fos.WriteFully(vertex_color,vertex_color_size);

            delete[] vertex_color;
        }

        if(mtl->uv_use.GetCount()>0
         &&mesh->GetNumUVChannels())
        {
            int tc=0;
            int comp_total=0;
            uint *uv_use=mtl->uv_use.GetData();

            //这里要重新审视数据来源，并不是每一个纹理通道都有数据，并且和材质对应。
            //、、材质中的uv index具体对应啥 还不是很清楚

            for(int c=0;c<AI_MAX_NUMBER_OF_TEXTURECOORDS;c++)
            {
                if(uv_use[c]>=mesh->GetNumUVChannels())
                    uv_use[c]=0;

                comp_total+=mesh->mNumUVComponents[uv_use[c]];
            }

            comp_total*=mesh->mNumVertices;

            uint64 tc_size=mesh->GetNumUVChannels()+comp_total*sizeof(float);

            uint8 *tc_data=new uint8[tc_size];
            float *tp=(float *)(tc_data+mesh->GetNumUVChannels());
            for(int c=0;c<uv_channels;c++)
            {
                tc_data[c]=mesh->mNumUVComponents[uv_use[c]];

                SaveTexCoord(tp,mesh->mTextureCoords[c],mesh->mNumUVComponents[c],mesh->mNumVertices);

                tp+=mesh->mNumUVComponents[c]*mesh->mNumVertices;
            }

            fos.WriteFully(tc_data,tc_size);

            delete[] tc_data;
        }

        if(mesh->HasFaces())
        {
            if(mesh->mNumVertices>0xFFFF)
                SaveFaces<uint32>(&fos,mesh->mFaces,mesh->mNumFaces);
            else
                SaveFaces<uint16>(&fos,mesh->mFaces,mesh->mNumFaces);
        }

        fos.Close();
    }

    LOG_BR;
    LOG_INFO(OS_TEXT("TOTAL Vertices Count ")+OSString(vertex_total));
    LOG_INFO(OS_TEXT("TOTAL Faces Count ")+OSString(tri_total));
    LOG_INFO(OS_TEXT("TOTAL Bones Count ")+OSString(bone_total));

    LOG_INFO(OS_TEXT("TOTAL File Size ")+OSString(total_file_bytes));
    LOG_BR;
}

void AssimpLoader::LoadScene(const UTF8String &front,io::DataOutputStream *dos,const aiNode *nd)
{
    aiVector3D bb_min,bb_max;
    float box[6];
    get_bounding_box(nd,&bb_min,&bb_max);

    box[0]=bb_min.x;box[1]=bb_min.y;box[2]=bb_min.z;
    box[3]=bb_max.x;box[4]=bb_max.y;box[5]=bb_max.z;

    dos->WriteUTF8String(nd->mName.C_Str());
    dos->WriteFloat(box,6);

    dos->WriteFloat((float *)&(nd->mTransformation),16);

    dos->WriteUint32(nd->mNumMeshes);

    LOG_INFO(front+U8_TEXT("Node[")+UTF8String(nd->mName.C_Str())+U8_TEXT("][Mesh:")+UTF8String(nd->mNumMeshes)+U8_TEXT("][SubNode:")+UTF8String(nd->mNumChildren)+U8_TEXT("]"))

    const UTF8String new_front=U8_TEXT("  ")+front;

    if(nd->mNumMeshes>0)
    {
        dos->WriteUint32(nd->mMeshes,nd->mNumMeshes);

        for(unsigned int i=0;i<nd->mNumMeshes;i++)
        {
            const aiMesh *mesh=scene->mMeshes[nd->mMeshes[i]];

            LOG_INFO(new_front+U8_TEXT("Mesh[")+UTF8String(i)+U8_TEXT("] ")+UTF8String(mesh->mName.C_Str()));
        }
    }

    dos->WriteUint32(nd->mNumChildren);

    for(unsigned int n=0;n<nd->mNumChildren;++n)
        LoadScene(new_front,dos,nd->mChildren[n]);
}

bool AssimpLoader::LoadFile(const OSString &filename)
{
    uint filesize;
    char *filedata;

    filesize=filesystem::LoadFileToMemory(filename,(void **)&filedata);

    if(!filedata)
        return(false);

#ifdef _WIN32
    const UTF8String ext_name=ToUTF8String(filesystem::ClipFileExtName(filename));
#else
    const UTF8String ext_name=filesystem::ClipFileExtName(filename);
#endif//

    scene=aiImportFileFromMemory(filedata,filesize,aiProcessPreset_TargetRealtime_MaxQuality|aiProcess_FlipUVs,ext_name.c_str());

    delete[] filedata;

    if(!scene)
        return(false);

    filename.SubString(main_filename,0,filename.FindRightChar(OS_TEXT('.')));

    get_bounding_box(scene->mRootNode,&scene_min,&scene_max);

    scene_center.x = (scene_min.x + scene_max.x) / 2.0f;
    scene_center.y = (scene_min.y + scene_max.y) / 2.0f;
    scene_center.z = (scene_min.z + scene_max.z) / 2.0f;

    //这个顺序是假设了所有的材质和模型都有被使用
    //aiProcessPreset_TargetRealtime_Quality已经指定了会删除多余材质，所以这里不用处理。
    //但多余模型并不确定是否存在

    io::FileOutputStream fos;
    io::LEDataOutputStream dos(&fos);

    OSString scene_filename=main_filename+OS_TEXT(".scene");

    if(!fos.CreateTrunc(scene_filename))
    {
        LOG_INFO(OS_TEXT("Create Scene file Failed,filename: ")+scene_filename);
        return(false);
    }

    dos.WriteFully("SCENE\x1a\x01",7);

    dos.WriteUint32(scene->mNumMaterials);
    dos.WriteUint32(scene->mNumMeshes);

    LoadMaterial();                                     //载入所有材质

    dos.WriteUint32(tex_list.GetCount());

    LoadMesh();                                         //载入所有mesh
    LoadScene(UTF8String(""),&dos,scene->mRootNode);    //载入场景节点

    fos.Close();

    SaveTextures();

    return(true);
}
