Mercurial > hg > Game > Cerium
annotate Renderer/Engine/Collada.cc @ 1384:207e0ed76cf1 draft
minor changes.
author | e095732 <e095732@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 27 Jan 2012 02:10:52 +0900 |
parents | de990f3e0a21 |
children | 2247b81dd68f |
rev | line source |
---|---|
1376 | 1 #include "polygon.h" |
2 #include "SceneGraph.h" | |
3 #include "SceneGraph.cc" | |
4 #include "TextureHash.h" | |
5 #include "xml.h" | |
6 #include "SceneGraphRoot.h" | |
7 #include <iostream> | |
8 #include <SDL_image.h> | |
9 | |
10 using namespace std; | |
11 static TextureHash sgid_hash; | |
12 | |
13 extern int is_bmp(const char* name); | |
14 extern void make_black_alpha(SDL_Surface *texture_image); | |
15 | |
16 typedef struct source { | |
17 char *id; | |
18 union { | |
19 float *array; | |
20 char *alias; | |
21 }u; | |
22 int count; | |
23 struct source *next; | |
24 } SOURCE; | |
25 typedef SOURCE *SOURCE_P; | |
26 | |
27 typedef struct list { | |
28 SOURCE_P first; | |
29 SOURCE_P end; | |
30 } LIST; | |
31 typedef LIST *LIST_P; | |
32 | |
33 struct collada_state { | |
34 collada_state(){ | |
35 polylist = 0; | |
36 | |
37 vertex_offset = -1; | |
38 vertex_count = 0; | |
39 | |
40 normal_offset = -1; | |
41 normal_count = 0; | |
42 | |
43 texcoord_offset = -1; | |
44 texcoord_count = 0; | |
45 | |
46 polylist_count = 0; | |
47 vcsum = 0; | |
48 | |
49 limit = 0; | |
50 vmember = 0; | |
51 | |
52 images_flag=0; | |
53 } | |
54 int polylist; | |
55 int library_images; | |
56 xmlChar *vertices_id; | |
57 | |
58 char *vertex_src; | |
59 int vertex_offset; | |
60 int vertex_count; | |
61 | |
62 char *normal_src; | |
63 int normal_offset; | |
64 int normal_count; | |
65 | |
66 char *texcoord_src; | |
67 int texcoord_offset; | |
68 int texcoord_count; | |
69 | |
70 float *vcount; | |
71 float *pcount; | |
72 | |
73 SOURCE_P normal_float; | |
74 SOURCE_P vertex_float; | |
75 SOURCE_P texcoord_float; | |
76 | |
77 char *vertices_src; | |
78 int polylist_count; | |
79 | |
80 char *name; | |
81 char *tex_picname; | |
82 | |
83 int images_flag; | |
84 | |
85 int vcsum; | |
86 int limit; | |
87 int vmember; | |
88 }; | |
89 | |
90 /*static const char* | |
91 get_property(const char *name, xmlNodePtr cur){ | |
92 xmlAttr *p=cur->properties; | |
93 if (p==0) return ""; | |
94 for ( ;p; p=p->next) { | |
95 if ( xmlStrcmp(p->name, (xmlChar*)name) !=0 ) { | |
96 xmlNode* n=p->children; | |
97 if ( n==NULL ) return ""; | |
98 const char * v=(const char*)n->content; | |
99 if ( v==NULL ) return ""; | |
100 return v; | |
101 } | |
102 } | |
103 return ""; | |
104 }*/ | |
105 | |
106 SDL_Surface* | |
107 load_image(const char *file_name, const char *image_name) | |
108 { | |
109 int alpha_black = is_bmp(file_name); | |
110 /** | |
111 * image を 32bit(RGBA) に変換する | |
112 */ | |
113 SDL_Surface *texture_image = IMG_Load(file_name); | |
114 if (!texture_image) return 0; | |
115 SDL_Surface *tmpImage | |
116 = SDL_CreateRGBSurface(SDL_HWSURFACE, texture_image->w, | |
117 texture_image->h, 32, redMask, | |
118 greenMask, blueMask, alphaMask); | |
119 //= SDL_CreateRGBSurface(SDL_HWSURFACE, 0, | |
120 // 0, 32, redMask, | |
121 // greenMask, blueMask, alphaMask); | |
122 SDL_Surface *converted; | |
123 converted = SDL_ConvertSurface(texture_image, tmpImage->format, | |
124 SDL_HWSURFACE); | |
125 //SDL_SetAlpha(converted, 0, 0); | |
126 | |
127 if (converted != NULL) { | |
128 SDL_FreeSurface(texture_image); | |
129 texture_image = converted; | |
130 } | |
131 if (alpha_black) { | |
132 make_black_alpha(texture_image); | |
133 } | |
134 // this->gl_tex = SDL_GL_LoadTexture(texture_image); | |
135 return texture_image; | |
136 } | |
137 | |
138 /* add source list */ | |
139 static void | |
140 addSource(LIST_P list, SOURCE_P src) { | |
141 if (list->first == NULL && list->end == NULL) { | |
142 list->first = list->end = src; | |
143 return; | |
144 } | |
145 list->end->next = src; | |
146 list->end = src; | |
147 } | |
148 | |
149 /* compare a with b. Using to compare id */ | |
150 /* | |
151 static int | |
152 strcmp_a(const char *a, const char *b) | |
153 { | |
154 while (*a && *a++ == *b++); | |
155 if (*a) return 0; | |
156 return a[-1] > b[-1] ? 1:-1; | |
157 } | |
158 static float | |
159 get_point(char *id, int position, LIST_P list) | |
160 { | |
161 SOURCE_P cur = list->first; | |
162 for (;cur ; cur=cur->next) { | |
163 if (!strcmp_a(id, cur->id)) { | |
164 if (cur->count == 0) //alias | |
165 return get_point(cur->u.alias, position, list); | |
166 float *a = cur->u.array; | |
167 if (position <= cur->count) { | |
168 return a[position]; | |
169 } | |
170 } | |
171 } | |
172 } | |
173 */ | |
174 | |
175 static SOURCE_P | |
176 most_match(const char *id , LIST_P list) | |
177 { | |
178 SOURCE_P src = NULL; | |
179 SOURCE_P cur = NULL; | |
180 int tmplength = 0; | |
181 int strlength; | |
182 | |
183 for (cur=list->first ;cur!=list->end ;cur=cur->next) { | |
184 for (strlength=0;id[strlength]==cur->id[strlength];strlength++); | |
185 if (tmplength < strlength) { | |
186 tmplength = strlength; | |
187 src = cur; | |
188 } | |
189 } | |
1378 | 190 if (src == NULL){ |
191 fprintf(stderr,"not match"); | |
192 } | |
1376 | 193 return src; |
194 } | |
195 | |
196 void get_texture_image(char *filename, SceneGraphPtr sg, xmlNodePtr cur, TaskManager *manager) | |
197 { | |
198 char image_name[20] = "/tmp/image_XXXXXX"; | |
199 if (filename == NULL || filename[0] == 0) { | |
200 return; | |
201 } | |
202 /** | |
203 * image_name を既に Load していれば何もしない | |
204 */ | |
205 int tex_id; | |
206 /* ball test */ | |
1382 | 207 if (sgid_hash.sg_hash_regist(filename, tex_id) == -1) { |
208 SDL_Surface *texture_image = load_image(filename, image_name); | |
209 if (texture_image==0) { | |
1376 | 210 printf("Can't load image %s\n",filename); |
211 exit(0); | |
1382 | 212 } |
1376 | 213 sg->texture_info->texture_id = sg->makeTapestries(manager, texture_image, tex_id); |
1382 | 214 tex_id = sg->texture_info->texture_id; |
1376 | 215 if (unlink(image_name)) { |
1382 | 216 printf("unlink error\n"); |
1376 | 217 } |
218 } else { | |
219 /** | |
220 * 以前に Load されている Texture を共用 | |
221 */ | |
222 sg->texture_info->texture_id = tex_id; | |
223 } | |
1382 | 224 // 微妙に思う、自分で書き換えた感想 by gongo |
225 sg->texture_info->t_w = list[tex_id].t_w; | |
226 sg->texture_info->t_h = list[tex_id].t_h;; | |
227 sg->texture_info->pixels_orig = list[tex_id].pixels_orig; | |
228 sg->texture_info->pixels = list[tex_id].pixels; | |
229 sg->texture_info->scale_max = list[tex_id].scale_max; | |
230 sg->texture_info->texture_image = list[tex_id].texture_image; | |
1376 | 231 } |
232 | |
233 void decode_float_array(xmlNodePtr cur,LIST_P list){ | |
234 SOURCE_P src = (SOURCE_P)malloc(sizeof(SOURCE)); | |
235 char *id = (char*)xmlGetProp(cur, (xmlChar*)"id"); | |
236 src->id = (char*)xmlGetProp(cur, (xmlChar*)"id"); | |
237 | |
238 int count = atoi((char*)xmlGetProp(cur, (xmlChar*)"count")); | |
239 src->count = atoi((char*)xmlGetProp(cur, (xmlChar*)"count")); | |
240 src->u.array = new float[src->count]; | |
241 char *cont =(char*)xmlNodeGetContent(cur); | |
1384 | 242 |
1376 | 243 /* store float inpoint list */ |
244 for (int i = 0; cont != NULL; i++) { | |
245 cont = pickup_float(cont, src->u.array+i); | |
246 } | |
247 | |
248 src->next = NULL; | |
249 addSource(list, src); | |
1382 | 250 //printf("id:%s count:%d cont:%s\n", id, count, cont); |
1376 | 251 } |
252 | |
253 | |
254 void | |
255 get_points(xmlNodePtr cur, collada_state *s, TaskManager *manager){ | |
256 char *pcont = (char*)xmlNodeGetContent(cur); | |
257 for (int i = 0;i < s->polylist_count;i++){ | |
258 s->vcsum += s->vcount[i]; | |
259 s->vmember = i; | |
260 } | |
261 s->limit = s->vcsum * 2; | |
262 if (s->texcoord_offset == 2){ | |
263 s->limit = s->vcsum * 3; | |
264 } | |
265 s->pcount = new float[s->limit]; | |
266 for (int i=0;i<s->limit;i++){ | |
267 s->pcount[i] = 0; | |
268 } | |
269 for (int i=0; pcont != NULL; i++) { | |
270 pcont = pickup_float(pcont, s->pcount+i); | |
271 } | |
272 } | |
273 SceneGraph* | |
274 decode_points(collada_state *s, TaskManager *manager, SceneGraphPtr sg){ | |
275 int *vertexp; | |
276 vertexp = new int[s->vcsum]; | |
277 for (int i=0;i<s->vcsum;i++){ | |
278 vertexp[i]=0; | |
279 } | |
280 /* | |
281 * vertex_tableだけはpolygonを作る際にvcountが4の場合重複する点が | |
282 * 出てくるのでサイズを2倍用意しておく | |
283 */ | |
284 float *vertex_table; | |
285 float *normal_table; | |
286 float *texcoord_table; | |
287 vertex_table = new float[(s->vcsum)*2]; | |
288 normal_table = new float[s->vcsum]; | |
289 texcoord_table = new float[s->vcsum]; | |
290 for (int i=0;i < s->vcsum;i++){ | |
291 vertex_table[i] = 0; | |
292 normal_table[i] = 0; | |
293 texcoord_table[i] = 0; | |
294 } | |
295 | |
296 /** | |
297 * s->vcsum と s->vertex_float->countの値が違うので大きい方をとりあえず使っておく | |
298 */ | |
299 | |
300 /* p separate vertex position and nomal position. */ | |
301 if (s->texcoord_offset == 2){ | |
302 for (int i=0,j=0; i < s->limit; i+=3,j++) { | |
303 vertexp[j] = (int)s->pcount[i]; | |
304 normal_table[j] = s->normal_float->u.array[(int)s->pcount[i+1]]; | |
305 texcoord_table[j] = s->texcoord_float->u.array[(int)s->pcount[i+2]]; | |
306 } | |
307 } else{ | |
308 for (int i=0,j=0; i < s->limit; i+=2,j++) { | |
309 vertexp[j] = (int)s->pcount[i]; | |
310 normal_table[j] = s->normal_float->u.array[(int)s->pcount[i+1]]; | |
311 } | |
312 } | |
313 | |
314 /* make triangle */ | |
1379
13065ad17328
collada moved but only my mac.
e095732 <e095732@ie.u-ryukyu.ac.jp>
parents:
1378
diff
changeset
|
315 int k=0,l=0,size=0; |
1376 | 316 for (int i=0;i<s->vmember;i++) { |
317 if (s->vcount[i] == 4) { | |
318 vertex_table[k++] = s->vertex_float->u.array[vertexp[l]]; | |
319 vertex_table[k++] = s->vertex_float->u.array[vertexp[l+1]]; | |
320 vertex_table[k++] = s->vertex_float->u.array[vertexp[l+2]]; | |
321 vertex_table[k++] = s->vertex_float->u.array[vertexp[l+1]]; | |
322 vertex_table[k++] = s->vertex_float->u.array[vertexp[l+2]]; | |
323 vertex_table[k++] = s->vertex_float->u.array[vertexp[l+3]]; | |
324 l+=4; | |
1379
13065ad17328
collada moved but only my mac.
e095732 <e095732@ie.u-ryukyu.ac.jp>
parents:
1378
diff
changeset
|
325 size +=2; |
1376 | 326 } else if (s->vcount[i]==3) { |
327 vertex_table[k++] = s->vertex_float->u.array[vertexp[l++]]; | |
328 vertex_table[k++] = s->vertex_float->u.array[vertexp[l++]]; | |
329 vertex_table[k++] = s->vertex_float->u.array[vertexp[l++]]; | |
1379
13065ad17328
collada moved but only my mac.
e095732 <e095732@ie.u-ryukyu.ac.jp>
parents:
1378
diff
changeset
|
330 size++; |
1376 | 331 } |
332 } | |
333 | |
334 /** | |
335 * (SceneGraph.cc) | |
336 * pickup_normal,pickup_coordinate,pickup_textureの処理 | |
337 * vcsumは頂点の数,countは面の数 | |
338 */ | |
1384 | 339 |
1379
13065ad17328
collada moved but only my mac.
e095732 <e095732@ie.u-ryukyu.ac.jp>
parents:
1378
diff
changeset
|
340 int count = size / 3; |
1376 | 341 //polygonの作成 |
342 sg->pp_num = (count + MAX_SIZE_TRIANGLE - 1) / MAX_SIZE_TRIANGLE; | |
343 sg->pp = new PolygonPack[sg->pp_num]; | |
1379
13065ad17328
collada moved but only my mac.
e095732 <e095732@ie.u-ryukyu.ac.jp>
parents:
1378
diff
changeset
|
344 sg->name = s->name; |
13065ad17328
collada moved but only my mac.
e095732 <e095732@ie.u-ryukyu.ac.jp>
parents:
1378
diff
changeset
|
345 sg->parent_name = "NULL"; |
13065ad17328
collada moved but only my mac.
e095732 <e095732@ie.u-ryukyu.ac.jp>
parents:
1378
diff
changeset
|
346 sg->size = size; |
1376 | 347 for (int i = 0;i < sg->pp_num; i++ ){ |
348 PolygonPackPtr pp = sg->pp; | |
349 TrianglePackPtr tri = pp[i].tri; | |
350 // TrianglePack の size のチェック | |
351 int tri_size = (count < MAX_SIZE_TRIANGLE) ? count : MAX_SIZE_TRIANGLE ; | |
352 pp[i].info.size = tri_size; | |
353 /* default texture peste */ | |
354 if (s->images_flag==0) { | |
1384 | 355 char *default_image = "../Test/xml_file/blend/images/ball.jpg"; |
356 get_texture_image(default_image, sg, (xmlNodePtr)NULL, manager); | |
1376 | 357 } |
358 int k = 0; | |
359 int m = 0; | |
360 int n = 0; | |
361 for (int j = 0; j < tri_size; j++) { | |
362 tri[j].normal1.x = normal_table[k++]; | |
363 tri[j].normal1.y = normal_table[k++]; | |
364 tri[j].normal1.z = normal_table[k++]; | |
365 | |
366 tri[j].normal2.x = normal_table[k++]; | |
367 tri[j].normal2.y = normal_table[k++]; | |
368 tri[j].normal2.z = normal_table[k++]; | |
369 | |
370 tri[j].normal3.x = normal_table[k++]; | |
371 tri[j].normal3.y = normal_table[k++]; | |
372 tri[j].normal3.z = normal_table[k++]; | |
373 | |
374 tri[j].ver1.tex_x = texcoord_table[m++]; | |
375 tri[j].ver1.tex_y = texcoord_table[m++]; | |
376 | |
377 tri[j].ver2.tex_x = texcoord_table[m++]; | |
378 tri[j].ver2.tex_y = texcoord_table[m++]; | |
379 | |
380 tri[j].ver3.tex_x = texcoord_table[m++]; | |
381 tri[j].ver3.tex_y = texcoord_table[m++]; | |
382 | |
383 tri[j].ver1.x = vertex_table[n++]; | |
384 tri[j].ver1.y = vertex_table[n++]; | |
385 tri[j].ver1.z = vertex_table[n++]; | |
386 | |
387 tri[j].ver2.x = vertex_table[n++]; | |
388 tri[j].ver2.y = vertex_table[n++]; | |
389 tri[j].ver2.z = vertex_table[n++]; | |
390 | |
391 tri[j].ver3.x = vertex_table[n++]; | |
392 tri[j].ver3.y = vertex_table[n++]; | |
393 tri[j].ver3.z = vertex_table[n++]; | |
394 | |
395 } | |
396 | |
397 } | |
398 sg->c_xyz[0] = sg->c_xyz[1] = sg->c_xyz[2] = 0; | |
1384 | 399 |
1376 | 400 delete []vertexp; |
401 delete []vertex_table; | |
402 delete []normal_table; | |
403 delete []texcoord_table; | |
404 | |
405 /* got out of polylist */ | |
406 s->polylist = 0; | |
407 return sg; | |
408 } | |
409 | |
410 static void | |
411 xml_walk(xmlNodePtr cur, struct collada_state *s, LIST_P list,SceneGraphPtr sg, SceneGraphRoot *root) | |
412 { | |
413 int in_polylist=0; | |
414 if (!xmlStrcmp(cur->name, (xmlChar*)"polylist")) { | |
415 s->polylist_count = atoi((char*)xmlGetProp(cur, (xmlChar*)"count")); | |
416 s->polylist=1; | |
417 in_polylist=1; | |
418 } else if (!xmlStrcmp(cur->name, (xmlChar*)"vertices")) { | |
419 s->vertices_id = xmlGetProp(cur, (xmlChar*)"id"); | |
420 } else if (!xmlStrcmp(cur->name, (xmlChar*)"library_images")) { | |
1378 | 421 s->library_images=1; |
422 //library_images is wrote at texture image name. only use one image file | |
1376 | 423 } else if (s->library_images && !xmlStrcmp(cur->name, (xmlChar*)"init_from")) { |
424 s->tex_picname = (char*)xmlGetProp(cur, (xmlChar*)"init_from"); | |
425 get_texture_image(s->tex_picname, sg, cur , root->tmanager); | |
426 s->library_images=0; | |
427 s->images_flag=1; | |
428 } else if (!s->polylist && !xmlStrcmp(cur->name, (xmlChar*)"input")) { | |
429 char *semantic = (char*)xmlGetProp(cur, (xmlChar*)"semantic"); | |
430 if (!xmlStrcmp((xmlChar*)semantic, (xmlChar*)"POSITION")) { | |
431 s->vertices_src = (char*)xmlGetProp(cur, (xmlChar*)"source"); | |
432 } | |
433 } else if (s->polylist && !xmlStrcmp(cur->name, (xmlChar*)"input")) { | |
434 char *semantic = (char*)xmlGetProp(cur, (xmlChar*)"semantic"); | |
435 if (!xmlStrcmp((xmlChar*)semantic, (xmlChar*)"VERTEX")) { | |
436 s->vertex_src = (char*)xmlGetProp(cur, (xmlChar*)"source"); | |
437 s->vertex_float = most_match(s->vertices_src+1, list); | |
438 } else if (!xmlStrcmp((xmlChar*)semantic, (xmlChar*)"NORMAL")) { | |
439 s->normal_src = (char*)xmlGetProp(cur, (xmlChar*)"source"); | |
440 s->normal_offset = atoi((char*)xmlGetProp(cur, (xmlChar*)"offset")); | |
441 s->normal_float = most_match(s->normal_src+1, list); | |
442 } else if (!xmlStrcmp((xmlChar*)semantic, (xmlChar*)"TEXCOORD")) { | |
443 s->texcoord_src = (char*)xmlGetProp(cur, (xmlChar*)"source"); | |
444 s->texcoord_offset = atoi((char*)xmlGetProp(cur, (xmlChar*)"offset")); | |
445 s->texcoord_float = most_match(s->texcoord_src+1, list); | |
446 } | |
447 } else if (!xmlStrcmp(cur->name, (xmlChar*)"vcount")) { | |
448 char *vcont = (char*)xmlNodeGetContent(cur); | |
449 s->vcount = new float[s->polylist_count]; | |
450 for (int i=0; vcont!=NULL; i++) { | |
451 /* store vcount list */ | |
452 vcont = pickup_float(vcont, s->vcount+i); | |
453 } | |
454 } else if (!xmlStrcmp(cur->name, (xmlChar*)"p")) { | |
455 get_points(cur,s,root->tmanager); | |
456 in_polylist = 0; | |
457 } else if (!xmlStrcmp(cur->name, (xmlChar*)"float_array")) { | |
458 decode_float_array(cur,list); | |
459 } else if (!xmlStrcmp(cur->name, (xmlChar*)"node" )) { | |
460 s->name = (char*)xmlGetProp(cur, (xmlChar*)"id"); | |
461 } | |
462 for (cur=cur->children; cur; cur=cur->next){ | |
463 xml_walk(cur,s,list,sg,root); | |
464 } | |
465 } | |
466 void | |
467 init_list(LIST_P list) { | |
468 list->first = NULL; | |
469 list->end = NULL; | |
470 } | |
471 | |
472 | |
473 void | |
474 SceneGraphRoot::createFromCOLLADAfile(TaskManager *manager, const char *xmlColladafile) | |
475 { | |
476 /*make parse dom*/ | |
477 xmlDocPtr doc; | |
478 xmlNodePtr cur; | |
479 | |
480 doc = xmlParseFile(xmlColladafile); | |
481 cur = xmlDocGetRootElement(doc); | |
482 | |
483 if (xmlStrcmp(cur->name, (xmlChar*)"COLLADA")){ | |
484 return ; | |
485 } | |
486 | |
487 /* node analyze */ | |
488 struct collada_state s; | |
489 SceneGraphPtr sg = new SceneGraph(manager); | |
490 for (cur=cur->children; cur; cur=cur->next){ | |
491 LIST list; | |
492 init_list(&list); | |
493 xml_walk(cur,&s,&list,sg,this); | |
494 } | |
495 registSceneGraph(decode_points(&s,manager,sg)); | |
496 xmlFreeDoc(doc); | |
497 } |