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