Mercurial > hg > Game > Cerium
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); +}