changeset 1376:ae0398dd61d2 draft

add Collada.cc
author Taiki TAIRA <e095767@ie.u-ryukyu.ac.jp>
date Thu, 26 Jan 2012 18:38:37 +0900
parents 07e5f03d0eaa
children 22794a7f26a3
files Renderer/Engine/Collada.cc
diffstat 1 files changed, 500 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Renderer/Engine/Collada.cc	Thu Jan 26 18:38:37 2012 +0900
@@ -0,0 +1,500 @@
+#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;
+
+    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;
+};
+
+/*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;
+
+    if (src == NULL){
+      fprintf(stderr,"not match");
+    }
+    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;
+        }
+    }
+    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));
+    char *id = (char*)xmlGetProp(cur, (xmlChar*)"id");
+    src->id = (char*)xmlGetProp(cur, (xmlChar*)"id");
+    
+    int count = atoi((char*)xmlGetProp(cur, (xmlChar*)"count"));
+    src->count = atoi((char*)xmlGetProp(cur, (xmlChar*)"count"));
+    src->u.array = new float[src->count];
+    char *cont =(char*)xmlNodeGetContent(cur);
+    //const char *id = get_property("id", cur);
+    //int count = atoi(get_property("count", 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;
+    }
+    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){
+    int *vertexp;
+    vertexp = new int[s->vcsum];
+    for (int i=0;i<s->vcsum;i++){
+       vertexp[i]=0;
+    }
+    /*
+     * vertex_tableだけはpolygonを作る際にvcountが4の場合重複する点が
+     * 出てくるのでサイズを2倍用意しておく
+     */
+    float *vertex_table;
+    float *normal_table;
+    float *texcoord_table; 
+    vertex_table = new float[(s->vcsum)*2];
+    normal_table = new float[s->vcsum];
+    texcoord_table = new float[s->vcsum];
+    for (int i=0;i < s->vcsum;i++){
+        vertex_table[i] = 0;
+	normal_table[i] = 0;
+	texcoord_table[i] = 0;
+    }
+
+    /**
+     * 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++) {
+	    vertexp[j] = (int)s->pcount[i];
+	    normal_table[j] = s->normal_float->u.array[(int)s->pcount[i+1]];
+	    texcoord_table[j] = s->texcoord_float->u.array[(int)s->pcount[i+2]];
+	}
+    } else{
+        for (int i=0,j=0; i < s->limit; i+=2,j++) {
+	    vertexp[j] = (int)s->pcount[i];
+	    normal_table[j] = s->normal_float->u.array[(int)s->pcount[i+1]];
+	}
+    }
+
+    /* make triangle */
+    int k=0,l=0;
+    for (int i=0;i<s->vmember;i++) {
+        if (s->vcount[i] == 4) {
+            vertex_table[k++] = s->vertex_float->u.array[vertexp[l]];
+            vertex_table[k++] = s->vertex_float->u.array[vertexp[l+1]];
+            vertex_table[k++] = s->vertex_float->u.array[vertexp[l+2]];
+            vertex_table[k++] = s->vertex_float->u.array[vertexp[l+1]];
+            vertex_table[k++] = s->vertex_float->u.array[vertexp[l+2]];
+            vertex_table[k++] = s->vertex_float->u.array[vertexp[l+3]];
+            l+=4;
+        } else if (s->vcount[i]==3) {
+            vertex_table[k++] = s->vertex_float->u.array[vertexp[l++]];
+            vertex_table[k++] = s->vertex_float->u.array[vertexp[l++]];
+            vertex_table[k++] = s->vertex_float->u.array[vertexp[l++]];
+        }
+    }
+
+   /**
+     * (SceneGraph.cc)
+     * pickup_normal,pickup_coordinate,pickup_textureの処理
+     * vcsumは頂点の数,countは面の数
+     */
+    int count = s->vcsum / 3; 
+    //polygonの作成
+    sg->pp_num = (count + MAX_SIZE_TRIANGLE - 1) / MAX_SIZE_TRIANGLE;
+    sg->pp = new PolygonPack[sg->pp_num];
+    
+    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) {
+        get_texture_image("default.jpg", 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;
+    
+    //int tex_id = 0;
+    //sgid_hash.sg_hash_regist(s->name, tex_id);
+ 
+    delete []vertexp;
+    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;
+    printf("name = %s, child:%s\n", (char *)cur->name, (char *)cur->children);
+    printf("s->polylist = %d\n",s->polylist);
+    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);
+        printf("------------------%s",s->tex_picname);
+        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;
+    //,cur_images,cur_effects,cur_geometries,cur_visual_scenes;
+    //SceneGraphPtr tmp;
+    
+    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);
+}