view Renderer/Engine/Collada.cc @ 1391:1ea6e4eb2b0a draft

remove error.
author e095732 <e095732@ie.u-ryukyu.ac.jp>
date Fri, 27 Jan 2012 18:23:56 +0900
parents b4f6539fecf6
children 555d2a31cf0c
line wrap: on
line source

#include "polygon.h"
#include "SceneGraph.h" 
#include "SceneGraph.cc" 
#include "TextureHash.h"
#include "xml.h"
#include "SceneGraphRoot.h"
#include <iostream>
#include <SDL_image.h>

using namespace std;
static TextureHash sgid_hash;

extern int is_bmp(const char* name);
extern void make_black_alpha(SDL_Surface *texture_image);

typedef struct source {
    char *id;
    union {
        float *array;
        char *alias;
    }u;
    int count;
    struct source *next;
} SOURCE;
typedef SOURCE *SOURCE_P;

typedef struct list {
    SOURCE_P first;
    SOURCE_P end;
} LIST;
typedef LIST *LIST_P;

struct collada_state {
    collada_state(){
        polylist = 0;

        vertex_offset = -1;
        vertex_count = 0;

	normal_offset = -1;
	normal_count = 0;

	texcoord_offset = -1;
	texcoord_count = 0; 
	
	polylist_count = 0;
	vcsum = 0;

	limit = 0;
	vmember = 0;
	vtable_size =0;

    images_flag=0;
    }
    int polylist;
    int library_images;
    xmlChar *vertices_id;

    char *vertex_src;
    int vertex_offset;
    int vertex_count;

    char *normal_src;
    int normal_offset;
    int normal_count;

    char *texcoord_src;
    int texcoord_offset;
    int texcoord_count;
  
    float *vcount;
    float *pcount;
  
    SOURCE_P normal_float;
    SOURCE_P vertex_float;
    SOURCE_P texcoord_float;

    char *vertices_src;
    int polylist_count;
 
    char *name;
    char *tex_picname;

    int images_flag; 

    int vcsum;
    int limit;
    int vmember;
    int vtable_size;
};

/*static const char*
get_property(const char *name, xmlNodePtr cur){
   xmlAttr *p=cur->properties; 
   if (p==0) return "";
   for ( ;p; p=p->next) {
       if ( xmlStrcmp(p->name, (xmlChar*)name) !=0 ) {
	   xmlNode* n=p->children;
	  if ( n==NULL ) return "";
	  const char * v=(const char*)n->content;
	  if ( v==NULL ) return "";
	  return v;
       }
   }
   return "";
}*/

SDL_Surface*
load_image(const char *file_name, const char *image_name)
{
    int alpha_black =  is_bmp(file_name);
/**
 * image を 32bit(RGBA) に変換する
 */
    SDL_Surface *texture_image = IMG_Load(file_name);
    if (!texture_image) return 0;
    SDL_Surface *tmpImage
        = SDL_CreateRGBSurface(SDL_HWSURFACE, texture_image->w,
                             texture_image->h, 32, redMask,
                            greenMask, blueMask, alphaMask);
      //= SDL_CreateRGBSurface(SDL_HWSURFACE, 0,
      //                       0, 32, redMask,
      //                       greenMask, blueMask, alphaMask);
    SDL_Surface *converted;
    converted = SDL_ConvertSurface(texture_image, tmpImage->format,
                                   SDL_HWSURFACE);
    //SDL_SetAlpha(converted, 0, 0);

    if (converted != NULL) {
        SDL_FreeSurface(texture_image);
        texture_image = converted;
    }
    if (alpha_black) {
	make_black_alpha(texture_image);
    }
    // this->gl_tex = SDL_GL_LoadTexture(texture_image);
    return texture_image;
}

/* add source list */
static void
addSource(LIST_P list, SOURCE_P src) {
    if (list->first == NULL && list->end == NULL) {
        list->first = list->end = src;
        return;
    }
    list->end->next = src;
    list->end = src;
}

/* compare a with b. Using to compare id */
/*
static int
strcmp_a(const char *a, const char *b)
{
    while (*a && *a++ == *b++);
    if (*a) return 0;
    return a[-1] > b[-1] ? 1:-1;
}
static float
get_point(char *id, int position, LIST_P list)
{
    SOURCE_P cur = list->first;
    for (;cur ; cur=cur->next) {
        if (!strcmp_a(id, cur->id)) {
            if (cur->count == 0) //alias 
                return get_point(cur->u.alias, position, list);
            float *a = cur->u.array;
            if (position <= cur->count) {
                return a[position];
            }
       }
    }
}
*/

static SOURCE_P
most_match(const char *id , LIST_P list)
{
    SOURCE_P src = NULL;
    SOURCE_P cur = NULL;
    int tmplength = 0;
    int strlength;

    for (cur=list->first ;cur!=list->end ;cur=cur->next) {
        for (strlength=0;id[strlength]==cur->id[strlength];strlength++); 
        if (tmplength < strlength) {
            tmplength = strlength;
            src = cur;
        }
    }
    if (src == NULL){
      fprintf(stderr,"not match");
    }
    return src;
}

void get_texture_image(char *filename, SceneGraphPtr sg,  xmlNodePtr cur, TaskManager *manager)
{
    char image_name[20] = "/tmp/image_XXXXXX";
    if (filename == NULL || filename[0] == 0) {
        return;
    }
    /**
     * image_name を既に Load していれば何もしない
     */
    int tex_id;
    /* ball test */
    if (sgid_hash.sg_hash_regist(filename, tex_id) == -1) {
        SDL_Surface *texture_image = load_image(filename, image_name);
	if (texture_image==0) {
	    printf("Can't load image %s\n",filename);
	    exit(0);
	}
        sg->texture_info->texture_id = sg->makeTapestries(manager, texture_image, tex_id);
	tex_id = sg->texture_info->texture_id;
        if (unlink(image_name)) {
	    printf("unlink error\n");
        }
    } else {
        /**
         * 以前に Load されている Texture を共用
         */
        sg->texture_info->texture_id = tex_id;
    }
    // 微妙に思う、自分で書き換えた感想 by gongo
    sg->texture_info->t_w = list[tex_id].t_w;
    sg->texture_info->t_h = list[tex_id].t_h;;
    sg->texture_info->pixels_orig = list[tex_id].pixels_orig;
    sg->texture_info->pixels = list[tex_id].pixels;
    sg->texture_info->scale_max = list[tex_id].scale_max;
    sg->texture_info->texture_image = list[tex_id].texture_image;
}
 
void decode_float_array(xmlNodePtr cur,LIST_P list){ 
    SOURCE_P src = (SOURCE_P)malloc(sizeof(SOURCE));
    src->id = (char*)xmlGetProp(cur, (xmlChar*)"id");
    
    src->count = atoi((char*)xmlGetProp(cur, (xmlChar*)"count"));
    src->u.array = new float[src->count];
    char *cont =(char*)xmlNodeGetContent(cur);

    /* store float inpoint list */
    for (int i = 0; cont != NULL; i++) {
        cont = pickup_float(cont, src->u.array+i);
    }

    src->next = NULL;
    addSource(list, src);
    //printf("id:%s count:%d cont:%s\n", id, count, cont);
}


void 
get_points(xmlNodePtr cur, collada_state *s, TaskManager *manager){
    char *pcont = (char*)xmlNodeGetContent(cur);
    for (int i = 0;i < s->polylist_count;i++){
       s->vcsum += s->vcount[i];
       s->vmember = i;
       if (s->vcount[i]==4){
	   s->vtable_size +=6;
       } else {
           s->vtable_size +=3;
       }
    }
    s->limit = s->vcsum * 2;
    if (s->texcoord_offset == 2){
        s->limit = s->vcsum * 3;
    }
    s->pcount = new float[s->limit];
    for (int i=0;i<s->limit;i++){
        s->pcount[i] = 0;
    }
    for (int i=0; pcont != NULL; i++) {
        pcont = pickup_float(pcont, s->pcount+i);
    }
}
SceneGraph*
decode_points(collada_state *s, TaskManager *manager, SceneGraphPtr sg){

    /*
     * vertex_tableだけはpolygonを作る際にvcountが4の場合重複する点が
     * 出てくるのでサイズを2倍用意しておく
     */
    float *vertex_table;
    float *normal_table;
    float *texcoord_table; 
    vertex_table = new float[s->vtable_size*3];
    normal_table = new float[s->vtable_size*3];
    texcoord_table = new float[s->vtable_size*2];
    bzero(vertex_table,sizeof(float)*s->vtable_size*3);
    bzero(normal_table,sizeof(float)*s->vtable_size*3);
    bzero(texcoord_table,sizeof(float)*s->vtable_size*2);

    /**
     * s->vcsum と s->vertex_float->countの値が違うので大きい方をとりあえず使っておく
     */

    /* p separate vertex position and nomal position. */
    if (s->texcoord_offset == 2){
        for (int i=0,j=0; i < s->limit; i+=3,j++) {
	    normal_table[j] = s->normal_float->u.array[(int)s->pcount[i+1]*3];
	    normal_table[j+1] = s->normal_float->u.array[(int)s->pcount[i+1]*3+1];
	    normal_table[j+2] = s->normal_float->u.array[(int)s->pcount[i+1]*3+2];
	    texcoord_table[j] = s->texcoord_float->u.array[(int)s->pcount[i+2]*2];
	    texcoord_table[j+1] = s->texcoord_float->u.array[(int)s->pcount[i+2]*2+1];
	}
    } else{
        for (int i=0,j=0; i < s->limit; i+=2,j++) {
	    normal_table[j] = s->normal_float->u.array[(int)s->pcount[i+1]*3];
	    normal_table[j+1] = s->normal_float->u.array[(int)s->pcount[i+1]*3+1];
	    normal_table[j+2] = s->normal_float->u.array[(int)s->pcount[i+1]*3+2];
	}
    }

    /* make triangle */
    int k=0,l=0,size=0;
    for (int i=0;i<s->vmember;i++) {
        if (s->vcount[i] == 4) {
	    vertex_table[k] = s->vertex_float->u.array[(int)s->pcount[i]*3];
            vertex_table[k+1] = s->vertex_float->u.array[(int)s->pcount[i]*3+1];
            vertex_table[k+2] = s->vertex_float->u.array[(int)s->pcount[i]*3+2];
            vertex_table[k+3] = s->vertex_float->u.array[(int)s->pcount[i+1]*3+0];
            vertex_table[k+4] = s->vertex_float->u.array[(int)s->pcount[i+1]*3+1];
            vertex_table[k+5] = s->vertex_float->u.array[(int)s->pcount[i+1]*3+2];
            vertex_table[k+6] = s->vertex_float->u.array[(int)s->pcount[i+3]*3+0];
            vertex_table[k+7] = s->vertex_float->u.array[(int)s->pcount[i+3]*3+1];
            vertex_table[k+8] = s->vertex_float->u.array[(int)s->pcount[i+3]*3+2];

            vertex_table[k+9] = s->vertex_float->u.array[(int)s->pcount[i]*3];
            vertex_table[k+10] = s->vertex_float->u.array[(int)s->pcount[i]*3+1];
            vertex_table[k+11] = s->vertex_float->u.array[(int)s->pcount[i]*3+2];
            vertex_table[k+12] = s->vertex_float->u.array[(int)s->pcount[i+3]*3+0];
            vertex_table[k+13] = s->vertex_float->u.array[(int)s->pcount[i+3]*3+1];
            vertex_table[k+14] = s->vertex_float->u.array[(int)s->pcount[i+3]*3+2];
            vertex_table[k+15] = s->vertex_float->u.array[(int)s->pcount[i+2]*3+0];
            vertex_table[k+16] = s->vertex_float->u.array[(int)s->pcount[i+2]*3+1];
            vertex_table[k+17] = s->vertex_float->u.array[(int)s->pcount[i+2]*3+2];
	    k+=18;
            l+=4;
	    size +=2;
        } else if (s->vcount[i]==3) {
	    vertex_table[k] = s->vertex_float->u.array[(int)s->pcount[i]*3];
            vertex_table[k+1] = s->vertex_float->u.array[(int)s->pcount[i]*3+1];
            vertex_table[k+2] = s->vertex_float->u.array[(int)s->pcount[i]*3+2];
            vertex_table[k+3] = s->vertex_float->u.array[(int)s->pcount[i+1]*3+0];
            vertex_table[k+4] = s->vertex_float->u.array[(int)s->pcount[i+1]*3+1];
            vertex_table[k+5] = s->vertex_float->u.array[(int)s->pcount[i+1]*3+2];
            vertex_table[k+6] = s->vertex_float->u.array[(int)s->pcount[i+2]*3+0];
            vertex_table[k+7] = s->vertex_float->u.array[(int)s->pcount[i+2]*3+1];
            vertex_table[k+8] = s->vertex_float->u.array[(int)s->pcount[i+2]*3+2];
	    k+=9;
	    size++;
        }
    }

   /**
     * (SceneGraph.cc)
     * pickup_normal,pickup_coordinate,pickup_textureの処理
     * vcsumは頂点の数,countは面の数
     */
   
    int count = size / 3;
    //polygonの作成
    sg->pp_num = (count + MAX_SIZE_TRIANGLE - 1) / MAX_SIZE_TRIANGLE;
    sg->pp = new PolygonPack[sg->pp_num];
    sg->name = s->name;
    sg->parent_name = "NULL";
    sg->size = size;
    for (int i = 0;i < sg->pp_num; i++ ){
    PolygonPackPtr pp = sg->pp;
	TrianglePackPtr tri =  pp[i].tri;
	// TrianglePack の size のチェック
        int tri_size = (count < MAX_SIZE_TRIANGLE) ? count : MAX_SIZE_TRIANGLE ;
	pp[i].info.size = tri_size;
    /* default texture peste */
    if (s->images_flag==0) {
        char *default_image = "../Test/xml_file/blend/images/ball.jpg"; 
        get_texture_image(default_image, sg, (xmlNodePtr)NULL, manager);
    }
	int k = 0;
	int m = 0;
	int n = 0;
	for (int j = 0; j < tri_size; j++) {
	    tri[j].normal1.x = normal_table[k++];
	    tri[j].normal1.y = normal_table[k++];
	    tri[j].normal1.z = normal_table[k++];
	    
	    tri[j].normal2.x = normal_table[k++];
	    tri[j].normal2.y = normal_table[k++];
	    tri[j].normal2.z = normal_table[k++];
	    
	    tri[j].normal3.x = normal_table[k++];
	    tri[j].normal3.y = normal_table[k++];
	    tri[j].normal3.z = normal_table[k++];
	    
	    tri[j].ver1.tex_x = texcoord_table[m++];
	    tri[j].ver1.tex_y = texcoord_table[m++];
	    
	    tri[j].ver2.tex_x = texcoord_table[m++];
	    tri[j].ver2.tex_y = texcoord_table[m++];
	    
	    tri[j].ver3.tex_x = texcoord_table[m++];
	    tri[j].ver3.tex_y = texcoord_table[m++];
	    
	    tri[j].ver1.x = vertex_table[n++];
	    tri[j].ver1.y = vertex_table[n++];
	    tri[j].ver1.z = vertex_table[n++];
	    
	    tri[j].ver2.x = vertex_table[n++];
	    tri[j].ver2.y = vertex_table[n++];
	    tri[j].ver2.z = vertex_table[n++];
	    
	    tri[j].ver3.x = vertex_table[n++];
	    tri[j].ver3.y = vertex_table[n++];
	    tri[j].ver3.z = vertex_table[n++];

	}
	
    }
    sg->c_xyz[0] = sg->c_xyz[1] = sg->c_xyz[2] = 0;

    delete []vertex_table;
    delete []normal_table;
    delete []texcoord_table;

    /* got out of polylist */
    s->polylist = 0;
    return sg;
}

static void 
xml_walk(xmlNodePtr cur, struct collada_state *s, LIST_P list,SceneGraphPtr sg, SceneGraphRoot *root)
{
    int in_polylist=0;
    if (!xmlStrcmp(cur->name, (xmlChar*)"polylist")) {
        s->polylist_count = atoi((char*)xmlGetProp(cur, (xmlChar*)"count"));
        s->polylist=1;
        in_polylist=1;
    } else if (!xmlStrcmp(cur->name, (xmlChar*)"vertices")) {
        s->vertices_id = xmlGetProp(cur, (xmlChar*)"id");
    } else if (!xmlStrcmp(cur->name, (xmlChar*)"library_images")) {
        s->library_images=1;
	//library_images is wrote at texture image name. only use one image file
    } else if (s->library_images && !xmlStrcmp(cur->name, (xmlChar*)"init_from")) { 
        s->tex_picname = (char*)xmlGetProp(cur, (xmlChar*)"init_from");
        get_texture_image(s->tex_picname, sg, cur , root->tmanager);
        s->library_images=0;
        s->images_flag=1;
    } else if (!s->polylist && !xmlStrcmp(cur->name, (xmlChar*)"input")) {
        char *semantic = (char*)xmlGetProp(cur, (xmlChar*)"semantic");
        if (!xmlStrcmp((xmlChar*)semantic, (xmlChar*)"POSITION")) {
	    s->vertices_src = (char*)xmlGetProp(cur, (xmlChar*)"source");
        }
    } else if (s->polylist && !xmlStrcmp(cur->name, (xmlChar*)"input")) {
	char *semantic = (char*)xmlGetProp(cur, (xmlChar*)"semantic");
        if (!xmlStrcmp((xmlChar*)semantic, (xmlChar*)"VERTEX")) {
	    s->vertex_src = (char*)xmlGetProp(cur, (xmlChar*)"source");
	    s->vertex_float = most_match(s->vertices_src+1, list);
        } else if (!xmlStrcmp((xmlChar*)semantic, (xmlChar*)"NORMAL")) {
            s->normal_src = (char*)xmlGetProp(cur, (xmlChar*)"source");
            s->normal_offset = atoi((char*)xmlGetProp(cur, (xmlChar*)"offset"));
            s->normal_float = most_match(s->normal_src+1, list);
        } else if (!xmlStrcmp((xmlChar*)semantic, (xmlChar*)"TEXCOORD")) {
            s->texcoord_src = (char*)xmlGetProp(cur, (xmlChar*)"source");
            s->texcoord_offset = atoi((char*)xmlGetProp(cur, (xmlChar*)"offset"));
            s->texcoord_float = most_match(s->texcoord_src+1, list);
	}
    } else if (!xmlStrcmp(cur->name, (xmlChar*)"vcount")) {
        char *vcont = (char*)xmlNodeGetContent(cur);
	s->vcount = new float[s->polylist_count];
        for (int i=0; vcont!=NULL; i++) {
	    /* store vcount list */
	    vcont = pickup_float(vcont, s->vcount+i);
        }
    } else if (!xmlStrcmp(cur->name, (xmlChar*)"p")) {
        get_points(cur,s,root->tmanager);
	in_polylist = 0;
    } else if (!xmlStrcmp(cur->name, (xmlChar*)"float_array")) {
        decode_float_array(cur,list);
    } else if (!xmlStrcmp(cur->name, (xmlChar*)"node" )) {
        s->name = (char*)xmlGetProp(cur, (xmlChar*)"id");
    }
    for (cur=cur->children; cur; cur=cur->next){
        xml_walk(cur,s,list,sg,root);
    }
}
void
init_list(LIST_P list) {
      list->first = NULL;
        list->end = NULL;
}


void
SceneGraphRoot::createFromCOLLADAfile(TaskManager *manager, const char *xmlColladafile)
{
    /*make parse dom*/
    xmlDocPtr doc;
    xmlNodePtr cur;
    
    doc = xmlParseFile(xmlColladafile);
    cur = xmlDocGetRootElement(doc);
    
    if (xmlStrcmp(cur->name, (xmlChar*)"COLLADA")){
        return ;
    }

    /* node analyze */
    struct collada_state s;
    SceneGraphPtr sg = new SceneGraph(manager);
    for (cur=cur->children; cur; cur=cur->next){
        LIST list;
        init_list(&list);
        xml_walk(cur,&s,&list,sg,this);
    }
    registSceneGraph(decode_points(&s,manager,sg));
    xmlFreeDoc(doc);
}