その他


//////////////////////// copy and paste from writefile.c //////////////////////

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "zlib.h"

#ifndef WIN32
#include <unistd.h>
#else
#include "winsock2.h"
#include "BLI_winstuff.h"
#include <io.h>
#include <process.h> // for getpid
#endif

#include <math.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "nla.h" //  __NLA is defined

#include "DNA_armature_types.h"
#include "DNA_action_types.h"
#include "DNA_actuator_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_color_types.h"
#include "DNA_constraint_types.h"
#include "DNA_controller_types.h"
#include "DNA_curve_types.h"
#include "DNA_customdata_types.h"
#include "DNA_effect_types.h"
#include "DNA_group_types.h"
#include "DNA_image_types.h"
#include "DNA_ipo_types.h"
#include "DNA_fileglobal_types.h"
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
#include "DNA_listBase.h" /* for Listbase, the type of samples, ...*/
#include "DNA_lamp_types.h"
#include "DNA_meta_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_material_types.h"
#include "DNA_modifier_types.h"
#include "DNA_nla_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
#include "DNA_oops_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_property_types.h"
#include "DNA_scene_types.h"
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sensor_types.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
#include "DNA_sound_types.h"
#include "DNA_texture_types.h"
#include "DNA_text_types.h"
#include "DNA_view3d_types.h"
#include "DNA_vfont_types.h"
#include "DNA_userdef_types.h"
#include "DNA_world_types.h"

#include "MEM_guardedalloc.h" // MEM_freeN
#include "BLI_blenlib.h"
#include "BLI_linklist.h"

#include "BKE_action.h"
#include "BKE_bad_level_calls.h" // build_seqar (from WHILE_SEQ) free_oops error
#include "BKE_blender.h"
#include "BKE_curve.h"
#include "BKE_customdata.h"
#include "BKE_constraint.h"
#include "BKE_global.h" // for G
#include "BKE_library.h" // for  set_listbasepointers
#include "BKE_main.h" // G.main
#include "BKE_node.h"
#include "BKE_packedFile.h" // for packAll
#include "BKE_screen.h" // for waitcursor
#include "BKE_scene.h" // for do_seq
#include "BKE_sound.h" /* ... and for samples */
#include "BKE_utildefines.h" // for defines
#include "BKE_modifier.h"
#include "BKE_idprop.h"
#ifdef WITH_VERSE
#include "BKE_verse.h"
#include "BIF_verse.h"
#endif

#include "GEN_messaging.h"

#include "readfile.h"
#include "genfile.h"

#include <errno.h>
////////////////////// End copy and paste /////////////////////////////////////

#include "BLO_writePB.h"

//Matrix Calc
#include "BLI_arithb.h"
//for update scene
#include "BKE_ipo.h"
#include "BKE_object.h"
#include "BKE_armature.h"
#include "BKE_key.h"

#include "BDR_editobject.h"
#include "bdr_drawaction.h"


#include "BLI_blenlib.h"
#include "BSE_editipo.h"
#include "BIF_keyframing.h"
#include "BIF_editaction.h"
#include "BIF_editarmature.h"

#include "float.h"

#include <vector>
#include <algorithm>
using namespace std;

#include <sstream>
#include <fstream>

#include "bdxutils.pb.h"
#include "bdxmesh.pb.h"
#include "bdxarmature.pb.h"


#pragma comment(lib,"libprotobuf.lib")
#pragma comment(lib,"libprotoc.lib")

//-----------------------------------------------------------------------------
// num of array elements
//-----------------------------------------------------------------------------
#define countof(array) (sizeof(array)/sizeof((array)[0]))

//-----------------------------------------------------------------------------
// deform pair
//-----------------------------------------------------------------------------
// def_nr, bone_index
typedef std::map<int, int> DeformMap;

typedef std::map<bdxproto::Subset*, std::vector<float>> SubsetVertsMap;

//-----------------------------------------------------------------------------
// macros for refreshing memory
//-----------------------------------------------------------------------------
#define SAFE_RELEASE(p) { if(p) { (p)->release(); (p)=NULL; } }
#define SAFE_RELEASE_ARRAY(p, size)\
{ \
    for (unsigned long i = 0; i < (size); ++i) \
    if( (p)[i] ) { (p)[i]->release(); (p)[i]=NULL; }\
}

#define SAFE_DELETE(p) { if(p) { delete(p); (p)=NULL; } }
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }


//-----------------------------------------------------------------------------
// utils
//-----------------------------------------------------------------------------

static float ROOT_MATRIX[][4] = {
    {1.0f, 0.0f, 0.0f, 0.0f},
    {0.0f, 0.0f, 1.0f, 0.0f},
    {0.0f, 1.0f, 0.0f, 0.0f},
    {0.0f, 0.0f, 0.0f, 1.0f},
};

typedef struct MeshData {
    Mesh *mesh;
    MFace *mface;
    MTFace *mtface;
    MCol *mcol;
    MDeformVert *mdvert;
} MeshData;

static void next_face(MeshData &data)
{
    if (data.mtface) { data.mtface += 1; }
    if (data.mcol) { data.mcol += 4; }
    if (data.mface) { data.mface += 1; }
}


//-----------------------------------------------------------------------------
// Armature
//-----------------------------------------------------------------------------

static void set_bone_params(bdxproto::Bone *dst, Bone *bone)
{
    float arm_mat_inv[4][4];
    Mat4Invert(arm_mat_inv, bone->arm_mat);

    // name
    dst->set_name(string(bone->name));
    
    // offset_matrix
    for (int i = 0; i < 4; ++i)
        for (int k = 0; k < 4; ++k)
            dst->add_offset_matrix(arm_mat_inv[i][k]);

    // head, tail
    for (int i = 0; i < 3; ++i) {
        dst->add_head(bone->arm_head[i]);
        dst->add_tail(bone->arm_tail[i]);
    }
}

static void append_bones(bdxproto::Bone *parent_bone, Bone *top_bone)
{
    for (Bone *bone = (Bone*)top_bone->childbase.first; bone; bone = bone->next) {
        if (!bone) break;
        bdxproto::Bone *dst = parent_bone->add_children();
        set_bone_params(dst, bone);
        append_bones(dst, bone);
    }
}


static void append_bposechannel(bdxproto::Channel *bdx_channel, bPoseChannel *channel, float ctime)
{
    bdx_channel->add_frame_key(ctime);
    
    float dst[4][4];
    Mat4CpyMat4(dst, channel->pose_mat);

    if (channel->parent != NULL) {
        float parent_inv[4][4];
        Mat4Invert(parent_inv, channel->parent->pose_mat);
        Mat4MulMat4(dst, channel->pose_mat, parent_inv);
    }

    for (int i = 0; i < 4; ++i)
        for (int k = 0; k < 4; ++k)
            bdx_channel->add_frame_matrix(dst[i][k]);
}

static void append_bpose(bdxproto::Armature *bdx_armature,
                         Object *arm_obj, bAction *action, bPose *pose, int optimize)
{
    if (action == NULL || action->id.us <= 0 || pose == NULL) return;

    //if (optimize & BLO_WRITEXML_BAKEIK) {
    //    bakeIK(arm_obj, action, pose);
    //}

    //if (optimize & BLO_WRITEXML_BAKEROOT) {
    //    bakeRoot(arm_obj, action, pose);
    //}

    // frame 1
    G.scene->r.cfra = 1;
    scene_update_for_newframe(G.scene, (1<<20) - 1);
    extract_pose_from_action (pose, action, bsystem_time(arm_obj, 1, 0.0));
    where_is_pose(arm_obj);

    bdxproto::Action *bdx_action = bdx_armature->add_action();

    bdx_action->set_name(string(action->id.name));
    bdx_action->set_arm_name(string(arm_obj->id.name));
    
    std::vector<float> keyList;
    std::vector<bdxproto::Channel*> bdx_channel_list;
    std::vector<bPoseChannel*> pose_channel_list;
    ListBase keyBase;

    // make keyList
    for (bPoseChannel *channel = (bPoseChannel*) pose->chanbase.first;
        channel; channel = channel->next)
    {
        // create & save channel
        bdxproto::Channel *bdx_channel = bdx_action->add_channel();
        bdx_channel->set_name(string(channel->name));
        
        bdx_channel_list.push_back(bdx_channel);
        pose_channel_list.push_back(channel);

        keyBase.first = keyBase.last = NULL;

        bActionChannel *ac = get_action_channel(action, channel->name);
        if (!ac) continue;

        ipo_to_keylist(ac->ipo, &keyBase, NULL, NULL);

        for (ActKeyColumn *ak = (ActKeyColumn*)keyBase.first; ak; ak = ak->next) {
            bool isFinded = FALSE;
            for (int n = 0; n < keyList.size(); ++n) {
                if (keyList[n] == ak->cfra){
                    isFinded = TRUE;
                    break;
                }
            }
            if (!isFinded) keyList.push_back(ak->cfra);
        }
        if (keyBase.first) BLI_freelistN(&keyBase);
    }

    // sort
    sort(keyList.begin(), keyList.end());

    for (int k = 0, kSize = keyList.size(); k < kSize; ++k) {
        float key = keyList[k];

        // do pose
        G.scene->r.cfra = (int) (key);
        //if (optimize & BLO_WRITEXML_CALC_MESH) {
        //    CLAMP(G.scene->r.cfra, 1, 300000);
        //    scene_update_for_newframe(G.scene, (1<<20) - 1);
        //}
        G.scene->r.cfra = (int) (key);

        extract_pose_from_action (pose, action, bsystem_time(arm_obj, G.scene->r.cfra, 0.0));
        where_is_pose(arm_obj);

        // if channel had the key, append frameMatrix
        int n = 0;
        for (bPoseChannel *channel = (bPoseChannel*) pose->chanbase.first;
            channel; channel = channel->next, ++n)
        {
            keyBase.first = keyBase.last = NULL;

            bActionChannel *ac = get_action_channel(action, channel->name);
            if (!ac) continue;
            ipo_to_keylist(ac->ipo, &keyBase, NULL, NULL);

            for (ActKeyColumn *ak = (ActKeyColumn*) keyBase.first; ak; ak = ak->next) {
                if ( ak->cfra == key) {
                    // found
                    append_bposechannel(bdx_channel_list[n], channel, key);
                    break;
                }
            }
            if (keyBase.first) BLI_freelistN(&keyBase);
        }
    }
}

static bool append_nlastrips(bdxproto::Armature *bdx_armature,
                             Object *arm_obj, int optimize)
{
    if (arm_obj->nlastrips.first == NULL) return false;

    // appended act list
    vector<bAction*> acts;
    
    int index = 0;
    for (bActionStrip *strip = (bActionStrip*)arm_obj->nlastrips.first;
        strip; strip = strip->next, ++index)
    {
    
        bdxproto::NLAStrip *bdx_strip = bdx_armature->add_strip();
        bdx_strip->set_start(strip->start);
        bdx_strip->set_end(strip->end);
        bdx_strip->set_act_start(strip->actstart);
        bdx_strip->set_act_end(strip->actend);
        bdx_strip->set_blend_in(strip->blendin);
        bdx_strip->set_blend_out(strip->blendout);
        bdx_strip->set_repeat(strip->repeat);
        bdx_strip->set_scale(strip->scale);

        if (strip->act == NULL) continue;
        
        int linked_index = -1;
        for (unsigned int i = 0; i < acts.size(); ++i) {
            if (strip->act == acts[i]) { linked_index = i; break; }
        }

        if (linked_index >= 0) {
            bdx_strip->set_linked_index(linked_index);
            bdx_strip->set_linked_name(acts[linked_index]->id.name);
            continue;
        }

        acts.push_back(strip->act);

        bdx_strip->set_linked_index(acts.size() - 1);

        short tmpFlag = arm_obj->nlaflag;
        arm_obj->nlaflag = arm_obj->nlaflag & (~OB_NLA_OVERRIDE);
        strip->flag |= ACTSTRIP_ACTIVE;

        bAction *tmpAction = arm_obj->action;
        arm_obj->action = strip->act;
        
        append_bpose(bdx_armature, arm_obj, strip->act, arm_obj->pose, optimize);

        strip->flag &= (~ACTSTRIP_ACTIVE);
        arm_obj->nlaflag = tmpFlag;
        arm_obj->action = tmpAction;
    }
    
    return true;
}

static bool append_barmature(bdxproto::Armature *bdx_armature,
                             Object *obj, bArmature *arm, bPose *pose, int option)
{
    if ( (!arm) || arm->id.us <= 0) return false;
    
    bdx_armature->set_name(arm->id.name);

    Bone *bone = (Bone*) arm->bonebase.first;
    if (!bone) return false;

    bdxproto::Bone *root_bone = bdx_armature->add_bone();
    set_bone_params(root_bone, bone);

    float root_offset[4][4];
    Mat4MulMat4(root_offset, obj->obmat, ROOT_MATRIX);

    for (int i = 0; i < 4; ++i)
        for (int k = 0; k < 4; ++k)
            root_bone->add_offset_matrix(root_offset[i][k]);

    append_bones(root_bone, bone);

    if (!append_nlastrips(bdx_armature, obj, option) ) {
        // export one default action (not NLA)
        append_bpose(bdx_armature, obj, obj->action, pose, option);
    }
    return true;
}

//-----------------------------------------------------------------------------
// Mesh
//-----------------------------------------------------------------------------

static void convert_mesh(bdxproto::Charactor *bdx_chara, Mesh *mesh, Object *obj)
{
    Object* arm = NULL;
    if (obj->parent && obj->parent->type == OB_ARMATURE) {
        arm = obj->parent;
    }    
}

int max_bones = 20;

static void float3xMat4(float v[3], float mat[][4])
{
    float x = v[0];
    float y = v[1];
    float z = v[2];

    v[0] =
        x * mat[0][0] +
        y * mat[1][0] +
        z * mat[2][0] +
        mat[3][0]
    ;

    v[1] =
        x * mat[0][1] +
        y * mat[1][1] +
        z * mat[2][1] +
        mat[3][1]
    ;

    v[2] =
        x * mat[0][2] +
        y * mat[1][2] +
        z * mat[2][2] +
        mat[3][2]
    ;
}


static bool append_face_data(bdxproto::Subset *subset,
                             Object *obj,
                             MeshData &data,
                             DeformMap& deform_map,
                             int v_num,
                             int pos)
{
    Mesh *mesh(data.mesh);
    MFace *mface(data.mface);
    MTFace *mtface(data.mtface);
    MCol *mcol(data.mcol);
    MDeformVert *mdvert(data.mdvert);
    
    // weight
    if (mdvert) {        
        for (int k = 0; k < mdvert->totweight; ++k) {
            int bone_index = deform_map[mdvert[v_num].dw[k].def_nr];
            float w = mdvert[v_num].dw[k].weight;

            bool is_founded = false;
            for (int n = 0, n_size = subset->bone_index_size(); n < n_size; ++n)
            {
                if (subset->bone_index(n) == bone_index) {
                    is_founded = true;
                    break;
                }
            }

            // max bones ?
            if ( !is_founded && (max_bones < subset->related_bone() + 1)) {
                // over max bones
                // therefore, return
                return false;
            } else if (!is_founded) {
                subset->set_related_bone(subset->related_bone() + 1);
            }

            subset->add_bone_index(bone_index);
            subset->add_weight(w);
        }
        subset->add_bone_weight_size(mdvert->totweight);
    }

    // uv
    if (mtface) {
        float uv[] = {
            mtface->uv[pos][0],
            1.0 - mtface->uv[pos][1],
        };
        subset->add_uv(uv[0]);
        subset->add_uv(uv[1]);
    } else if (subset->uv_size() > 0) {
        subset->add_uv(0.0);
        subset->add_uv(0.0);
    }

    // vertex
    float vert[3] = {
        mesh->mvert[v_num].co[0],
        mesh->mvert[v_num].co[1],
        mesh->mvert[v_num].co[2]
    };

    // normal
    float normal[3] = {
        - mesh->mvert[v_num].no[0],
        - mesh->mvert[v_num].no[1],
        - mesh->mvert[v_num].no[2]
    };

    // to left hand
    if (obj->parent && obj->parent->type == OB_ARMATURE) {
        float arm_mat_inv[4][4];
        Mat4Invert(arm_mat_inv, obj->parent->obmat);

        float3xMat4(vert, obj->obmat);
        float3xMat4(vert, arm_mat_inv);
        float3xMat4(normal, obj->obmat);
        float3xMat4(normal, arm_mat_inv);
        Normalize(normal);
    } else {
        float3xMat4(vert, obj->obmat);
        float3xMat4(vert, ROOT_MATRIX);
        float3xMat4(normal, obj->obmat);
        float3xMat4(normal, ROOT_MATRIX);
        Normalize(normal);
    }

    for (int i = 0; i < 3; ++i) {
        subset->add_vertex(vert[i]);
    }
    
    for (int i = 0; i < 3; ++i) {
        subset->add_normal(normal[i]);
    }

    // vertex color
    if (mcol) {
        MCol *c = mcol+pos;
        subset->add_vertex_color(c->r);
        subset->add_vertex_color(c->g);
        subset->add_vertex_color(c->b);
    }

    return true;
}

// if not found -> return -1
// else return mvert index
static int search_mvert_from_subset(bdxproto::Subset *subset,
                                    std::vector<float> &temp_verts,
                                    MVert *mv)
{
    for (int k = 0, k_size = temp_verts.size() / 3; k < k_size; ++k) {
        if ((temp_verts[k*3] == mv->co[0]) &&
            (temp_verts[k*3+1] == mv->co[1]) &&
            (temp_verts[k*3+2] == mv->co[2]) )
        {
            return k;
        }
    }
    return -1;
}

static bool append_triangle_face(
    bdxproto::Subset *subset,
    std::vector<float> &temp_verts,
    int offset,
    Object *obj,
    MeshData &data,
    DeformMap& deform_map)
{
    
    Mesh *mesh(data.mesh);
    MFace *mface(data.mface);
    MTFace *mtface(data.mtface);

    const float fac
        = VecLenf(mesh->mvert[mface->v1].co, mesh->mvert[mface->v2].co)
        - VecLenf(mesh->mvert[mface->v3].co, mesh->mvert[mface->v4].co);

    const int tri_pattern_a[] = { 2, 1, 0 };
    const int tri_pattern_b[] = { 2, 1, 0, 3, 2, 0 };
    const int tri_pattern_c[] = { 3, 1, 0, 3, 2, 1 };

    int v_len = (mface->v4) ? 6 : 3;
    int face[] = { -1, -1, -1, -1, -1, -1 };
    
    for (int i = offset; i < v_len; ++i) {
        int pos = 0;
        if (v_len < 3) {
            break;
        } else if (v_len == 3) {
            pos = tri_pattern_a[i];
        } else if (fac < FLT_EPSILON) {
            pos = tri_pattern_b[i];
        } else {
            pos = tri_pattern_c[i];
        }

        int v_num = 0;
        if (pos == 0) {
            v_num = mface->v1;
        } else if (pos == 1) {
            v_num = mface->v2;
        } else if (pos == 2) {
            v_num = mface->v3;
        } else if (pos == 3) {
            v_num = mface->v4;
        }
        
        // vertex is already existed ?
        int vertex_existed_index = search_mvert_from_subset(subset, temp_verts, &mesh->mvert[v_num]);

        if (vertex_existed_index >= 0)
        {
            if (mtface->uv) {
                // vertex's uv is already existed ?
                float pre_uv[] = {
                    subset->uv(vertex_existed_index*2 + 0),
                    subset->uv(vertex_existed_index*2 + 1),
                };
                bool is_same_uv = (
                    (mtface->uv[pos][0] == pre_uv[0]) &&
                    (1.0 - mtface->uv[pos][1] == pre_uv[1]) );

                if (is_same_uv) {
                    face[i] = vertex_existed_index;
                } else {                                
                    if ( !append_face_data(subset, obj, data, deform_map, v_num, pos) ) {
                        // over max bones capacity
                        return false;
                    }
                    // save verts
                    for (int k = 0; k < 3; ++k) {
                        temp_verts.push_back(data.mesh->mvert[v_num].co[k]);                            
                    }
                    // append face vert
                    face[i] = subset->vertex_size() / 3 - 1;
                }
            } else {
                face[i] = vertex_existed_index;
            }
        } else {
            if ( !append_face_data(subset, obj, data, deform_map, v_num, pos) ) {
                // over max bones capacity
                return false;
            }
            
            // save verts
            for (int k = 0; k < 3; ++k)    {
                temp_verts.push_back(data.mesh->mvert[v_num].co[k]);                            
            }
            // append face vert
            face[i] = subset->vertex_size() / 3 - 1;
        }
    }

    for (int i = 0, i_size = 6; i < i_size; ++i) {
        if (face[i] < 0) break;
        subset->add_face(face[i]);
    }

    return true;
}

static bdxproto::Subset* find_last_subset(bdxproto::Object *bdx_obj, Material *mat, int material_number)
{
    for (int k = bdx_obj->subset_size() - 1; k >= 0; --k) {
        if (mat &&
            bdx_obj->subset(k).material_number() == material_number &&
            bdx_obj->subset(k).name() == mat->id.name)
        {
            return bdx_obj->mutable_subset(k);
        }
    }
    return 0;
}

static string export_packed_image(Image *image, string &target_dir)
{
    PackedFile *pf = image->packedfile;
    string export_file_name(target_dir);
    string file_name(image->name);
    std::string::size_type last_bs = file_name.find_last_of("\\") + 1;
    file_name = file_name.substr(last_bs, file_name.size() - last_bs);
    export_file_name.append("\\").append(file_name);

    char* c = const_cast<char*>(export_file_name.c_str());
    if ( !BLI_exists(c) ) {    
        char buf[MAX_PATH];
        GetCurrentDirectory(MAX_PATH, buf);
        SetCurrentDirectory(target_dir.c_str());

        int dst = open(file_name.c_str(), O_BINARY + O_WRONLY + O_CREAT, 0666);
        if (dst > 0) {
            if (write(dst, pf->data, pf->size) != pf->size) {
                printf("Failed: export packed image\n");
            }
            close(dst);
        }
        SetCurrentDirectory(buf);
    }
    return file_name;
}

static string copy_image(Image *image, string &target_dir)
{
    string export_file_name(target_dir);
    string file_name(image->name);
    std::string::size_type last_bs = file_name.find_last_of("\\") + 1;
    file_name = file_name.substr(last_bs, file_name.size() - last_bs);
    export_file_name.append("\\").append(file_name);

    int src = open(image->name, O_BINARY + O_RDONLY);
    
    char* c = const_cast<char*>(export_file_name.c_str());
    if ( !BLI_exists(c) ) {
        if (src > 0) {
            int filelen = BLI_filesize(src);
            void* data;

            if (filelen != 0) {
                data = MEM_mallocN(filelen, "packFile");
                if (read(src, data, filelen) != filelen) {
                    if (data) MEM_freeN(data);
                    // failed
                }
                if (data) {
                    char buf[MAX_PATH];
                    GetCurrentDirectory(MAX_PATH, buf);
                    SetCurrentDirectory(target_dir.c_str());
                    int dst = open(file_name.c_str(), O_BINARY + O_WRONLY + O_CREAT, 0666);
                    if (dst > 0) {
                        if (write(dst, data, filelen)) {
                            // failed
                        }
                        close(dst);
                    }
                    SetCurrentDirectory(buf);
                }
            }
            if (data) MEM_freeN(data);
        }
    }
    if (src > 0) close(src);
    return file_name;
}

static void append_texture(bdxproto::Subset *subset, Material *mat, string &target_dir)
{
    for(int i = 0; i < MAX_MTEX; ++i)
    {
        if(mat->mtex[i] && mat->mtex[i]->tex) {
            Tex *tex= mat->mtex[i]->tex;
            if (!tex->ima) continue;
            
            string file_name;
            if (tex->ima->packedfile) {
                // export packed image
                file_name = export_packed_image(tex->ima, target_dir);
            } else     if ( BLI_exists(tex->ima->name) ) {
                // copy images from src to dst
                file_name = copy_image(tex->ima, target_dir);
            }

            // set file name if not existed
            bool found = false;
            for (int k = 0; k < subset->texture_path_size(); ++k) {
                if (subset->texture_path(k) == file_name) { found = true; }
            }
            if (!found) {
                subset->add_texture_path(file_name);
            }

        }
    }
}

static void append_node(bdxproto::Object *bdx_obj,
                        bdxproto::Subset *subset, Mesh *mesh, Material *mat, string &target_dir)
{
    //if (!mat) return;
    //if (!mat->nodetree) return;

    //if (bdx_obj->subset_size() == 1) {
    //    png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, user_error_fn, user_warning_fn);
    //    if (!png_ptr) return (ERROR);

    //    png_infop info_ptr = png_create_info_struct(png_ptr);
    //    if (!info_ptr) {
    //       png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
    //       return (ERROR);
    //    }


    //    string export_file_name(target_dir);
    //    string file_name("colorbands.png");
    //    export_file_name.append("\\").append(file_name);

    //    // open file
    //    FILE *fp = fopen(export_file_name.c_str(), "wb");
    //    if (!fp) {
    //        return (ERROR);
    //    }

    //    png_init_io(png_ptr, fp);
    //}

    //bNodeTree *ntree = mat->nodetree;
    //bNodeStack *stack= ntree->stack;

    //for(bNode *node= ntree->nodes.first; node; node= node->next) {
    //    if(node->typeinfo->gpufunc) {
    //        node_get_stack(node, stack, nsin, nsout);
    //        gpu_from_node_stack(&node->inputs, nsin, gpuin);
    //        gpu_from_node_stack(&node->outputs, nsout, gpuout);
    //        if(node->typeinfo->gpufunc(mat, node, gpuin, gpuout))
    //            data_from_gpu_stack(&node->outputs, nsout, gpuout);
    //    }
 // //      else if(node->type==NODE_GROUP && node->id) {
    //    //    node_get_stack(node, stack, nsin, nsout);
    //    //    gpu_node_group_execute(stack, mat, node, nsin, nsout);
    //    //}
    //}
}

static void set_material(bdxproto::Object *bdx_obj,
                         bdxproto::Subset *subset, Mesh *mesh, int material_number, string &target_dir)
{
    if (!subset) return;

    Material *mat = mesh->mat[material_number];
    
    subset->add_diffuse(mat->r);
    subset->add_diffuse(mat->g);
    subset->add_diffuse(mat->b);
    subset->add_speculer(mat->specr);
    subset->add_speculer(mat->specg);
    subset->add_speculer(mat->specb);
    subset->add_mirror(mat->mirr);
    subset->add_mirror(mat->mirg);
    subset->add_mirror(mat->mirb);

    append_texture(subset, mat, target_dir);
    append_node(bdx_obj, subset,mesh, mat, target_dir);
}

static void append_mface_and_material(bdxproto::Charactor *bdx_chara, Object *obj,
                                      DeformMap& deform_map, string &target_dir)
{
    
    static int a = 0;

    Mesh *mesh((Mesh*)obj->data);
    if (!mesh) return;
    if (!mesh->mface) return;
    if (!mesh->mvert) return;

    int tot_subset = 0;
    int tot_face = 0;

    MDeformVert *mdvert(NULL);

    
    float pre_time = ::timeGetTime();

    // find MDeformVert
    if (&mesh->vdata)
    {
        CustomData *data = &mesh->vdata;
    
        for (int i = 0; i < data->totlayer; ++i) {
            CustomDataLayer *layer = &(data->layers[i]);
            if (layer->type != CD_MDEFORMVERT) continue;
            mdvert = (MDeformVert*) layer->data;
        }
    }
    
    printf("find deform vert: %f seconds\n", (::timeGetTime() - pre_time) / 1000);

    MeshData data = { mesh, mesh->mface, mesh->mtface, mesh->mcol, mdvert };

    bdxproto::Object *bdx_obj = bdx_chara->mutable_object(bdx_chara->object_size()-1);

    int offset = 0;
    bool subset_dupli = false;
    int face_index = 0;
    
    SubsetVertsMap temp_verts_map;

    while (face_index < mesh->totface)
    {
        bdxproto::Subset *subset(NULL);
        Material *material(NULL);        
        int material_number = data.mface->mat_nr;

        if (mesh->mat && (*mesh->mat) ) {
            material = mesh->mat[material_number];
        }


        if ((data.mface->mat_nr < 255) && !subset_dupli) {
            subset = find_last_subset(bdx_obj, material, material_number);
        }

        if (!subset || face_index == 0 || subset_dupli) {
            // offset > 0 or subset not existed
            // then, create new subset

            subset = bdx_obj->add_subset();
            subset->set_material_number(material_number);
            subset->set_related_bone(0);
            subset->set_layer_number(obj->lay);
            
            if (material) {
                string material_name(material->id.name);
                subset->set_name(material_name);
                set_material(bdx_obj, subset, mesh, material_number, target_dir);
            } else {
                subset->set_name(mesh->id.name);
            }

            tot_subset++;
            temp_verts_map[subset];
            subset_dupli = false;
        }

        std::vector<float> & temp_verts = temp_verts_map[subset];

        // append !
        if (append_triangle_face(subset, temp_verts, offset, obj, data, deform_map)) {
            next_face(data);
            ++face_index;
            tot_face++;
        } else {
            subset_dupli = true;
            printf("subset dupli\n");
        }
    }
    tot_subset = tot_subset;
    printf("%s\n", mesh->id.name);
    printf("total subset: %d\n", tot_subset);
    printf("total faces: %d\n", tot_face);
    ++a;
}


static int get_bone_index(int &counter, string &vertex_group_name, Bone *top_bone)
{
    for (Bone *bone = (Bone*)top_bone->childbase.first; bone; bone = bone->next) {
        if (!bone) break;
        if (bone->name == vertex_group_name) { return counter; }
        ++counter;
        if (get_bone_index(counter, vertex_group_name, bone)) {
            return counter;
        }
    }
    return 0;
}

static void make_deform_map(Object *obj, DeformMap &deform_map)
{
    if (obj->parent &&
        obj->parent->type == OB_ARMATURE &&
        obj->parent->data &&
        &obj->defbase &&
        &obj->defbase.first)
    {
        bArmature *arm = (bArmature*)obj->parent->data;
        ListBase *defbase(&obj->defbase);
        int def_nr = 0;
        for (bDeformGroup *group = (bDeformGroup*)defbase->first; group; group = group->next, ++def_nr)
        {
            string name(group->name);
            if (!name.empty()) {
                int counter = 0;
                get_bone_index(counter, name, (Bone*) arm->bonebase.first);
                deform_map[def_nr] = counter;
            }
        }
    }
}

static void append_mesh(bdxproto::Charactor *bdx_charactor, Mesh *mesh, Object *obj, string &target_dir)
{
    if (!mesh || !obj) return;

    bdx_charactor->set_file_name(target_dir);

    if (obj->parent) {
        bdx_charactor->set_parent(string(obj->parent->id.name));
    } else {
        bdx_charactor->set_parent(string(""));
    }

    bdx_charactor->set_is_shader_skinning_enable(true);
    
    float pre_time = ::timeGetTime();

    // 1st : create deform map (pairs of deform numbers)
    DeformMap deform_map;
    make_deform_map(obj, deform_map);

    printf("make deform map: %f seconds\n", (::timeGetTime() - pre_time) / 1000);

    // 2nd : copy mesh to bdx
    append_mface_and_material(bdx_charactor, obj, deform_map, target_dir);

}

static void set_subset_parameters(bdxproto::Charactor *bdx_charactor)
{
    bdxproto::Subset *pre_subset = NULL;
    for (int k = 0, k_size = bdx_charactor->object_size(); k < k_size; ++k) {
        bdxproto::Object* bdx_obj = bdx_charactor->mutable_object(k);
        for (int i = 0, i_size = bdx_obj->subset_size(); i < i_size; ++i)
        {
            bdxproto::Subset *subset = bdx_obj->mutable_subset(i);

            // set object parameters
            int fsize = bdx_obj->all_face_size() + subset->face_size() / 3;
            bdx_obj->set_all_face_size(fsize);
            int vsize = bdx_obj->all_vertex_size() + subset->vertex_size() / 3;
            bdx_obj->set_all_vertex_size(vsize);

            if (subset->vertex_color_size() > 0) {
                bdx_obj->set_has_vertex_color(true);
            }
            if (subset->uv_size() > 0) {
                bdx_obj->set_has_uv(true);
            }
            if (subset->weight_size() > 0) {
                bdx_obj->set_has_weight(true);
            }

            // set subset parameters
            if (pre_subset) {
                subset->set_first_face(pre_subset->first_face() + pre_subset->face_size() / 3);
                subset->set_first_vertex(pre_subset->first_vertex() + pre_subset->vertex_size() / 3);

                int offset = subset->first_vertex();
                for (int k = 0, k_size = subset->face_size(); k < k_size; ++k) {
                    subset->mutable_face()->Set(k, subset->face(k) + offset);
                }

            } else {
                subset->set_first_face(0);
                subset->set_first_vertex(0);
            }

            pre_subset = subset;
        }
    }
}

//-----------------------------------------------------------------------------
// objects
//-----------------------------------------------------------------------------

void append_objects(string &target_dir, ListBase *idbase, int type)
{
    // document
    bdxproto::Charactor *bdx_charactor = NULL;
    bdxproto::Object *bdx_obj = NULL;
    bdxproto::Armature *bdx_armature = NULL;

    float pre_time = ::timeGetTime();

    // dir name
    int pos = target_dir.find_last_of("\\") + 1;
    string dir_name(target_dir.substr(pos, target_dir.length() - pos));

    // target file str
    string mesh_str(target_dir + "\\" + "mesh.pb");
    string armature_str(target_dir + "\\" + "armature.pb");
    string camera_str(target_dir + "\\" + "camera.pb");
    string empty_str(target_dir + "\\" + "empty.pb");
    string lamp_str(target_dir + "\\" + "lamp.pb");

    /// create document par object
    for (Object *ob = (Object *)idbase->first; ob; ob = (Object *)ob->id.next)
    {
        if (ob->id.us <= 0) continue;
        // not export 1st @ obj
        if (strncmp(ob->id.name, "OB@", 3) == 0) { continue; }

        if (ob->type == OB_MESH && (type & BLO_WRITE_PB_MESH)) {
            if (bdx_charactor == NULL) {
                bdx_charactor = new bdxproto::Charactor();
                bdx_obj = bdx_charactor->add_object();
                bdx_obj->set_name(string(ob->id.name));
            }

            G.scene->r.cfra = 1;
            scene_update_for_newframe(G.scene, (1<<20) - 1);
            where_is_object(ob);
            do_ob_key(ob);

            append_mesh(bdx_charactor, (Mesh *) ob->data, ob, target_dir);
            //append_bdeformgroup(bdx_charactor, &ob->defbase);
        }

        if (ob->type == OB_ARMATURE && (type & BLO_WRITE_PB_ARMATURE)) {
            if (bdx_armature == NULL) { bdx_armature = new bdxproto::Armature(); }

            bdx_armature->set_name(string(ob->id.name));
            append_barmature(bdx_armature, ob, (bArmature *) ob->data, (bPose *) ob->pose, type);
        }
    }

    // set parameters
    if (bdx_charactor) {
        set_subset_parameters(bdx_charactor);
    }

    printf("convert: %f seconds\n", (::timeGetTime() - pre_time) / 1000);
    pre_time = ::timeGetTime();

    /// write documents
    if (bdx_armature) {
        fstream out(armature_str.c_str(), ios::out | ios::binary | ios::trunc);
        bdx_armature->SerializeToOstream(&out);
        out.close();
    }

    /// write documents
    if (bdx_charactor) {
        fstream out(mesh_str.c_str(), ios::out | ios::binary | ios::trunc);
        bdx_charactor->SerializeToOstream(&out);
        out.close();
    }

    printf("export: %f seconds\n", (::timeGetTime() - pre_time) / 1000);


failed:
    SAFE_DELETE(bdx_charactor);
    SAFE_DELETE(bdx_armature);
}


static int write_PB_handle(string &dir, int blo_write_pb_types) {
    // separated per file
    ListBase mainlist;
    blo_split_main(&mainlist, G.main);

    // dir name
    int pos = dir.find_last_of("\\") + 1;
    string name(dir.substr(pos, dir.length() - pos - 6));

    // target dir
    string target_dir(dir.substr(0, dir.length() - 6));

    // create directory( use win32api )
    if ( !CreateDirectory(target_dir.c_str(), NULL) ) {
        if ( ! (GetFileAttributes(target_dir.c_str()) & FILE_ATTRIBUTE_DIRECTORY) )
            return 0;
    }

    //if (blo_write_pb_types & BLO_WRITE_PB_WORLD) {
    //    append_worlds(pImpl, target_dir, &G.main->world);
    //}
    append_objects(target_dir, &G.main->object, blo_write_pb_types);

    return 1;
}


// return: success (1)
int BLO_write_PB(char *dir, int blo_write_pb_types, char **error_r) {
    int file, err, write_user_block;

    // xxx.blend
    string dir_s(dir);

    printf("test\n");

    if ( !write_PB_handle(dir_s, blo_write_pb_types) ) {
        *error_r = "Failed writing pb";
        return 0;
    }

    return 1;
}

Comments