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 */
|
1378
|
207 if (sgid_hash.sg_hash_regist(/*filename*/"Ball", tex_id) == -1) {
|
|
208 SDL_Surface *texture_image = load_image(filename, image_name);
|
1376
|
209 if (texture_image==0) {
|
|
210 printf("Can't load image %s\n",filename);
|
|
211 exit(0);
|
|
212 }
|
|
213 sg->texture_info->texture_id = sg->makeTapestries(manager, texture_image, tex_id);
|
|
214 tex_id = sg->texture_info->texture_id;
|
|
215 if (unlink(image_name)) {
|
|
216 printf("unlink error\n");
|
|
217 }
|
|
218 } else {
|
|
219 /**
|
|
220 * 以前に Load されている Texture を共用
|
|
221 */
|
|
222 sg->texture_info->texture_id = tex_id;
|
|
223 }
|
|
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;
|
|
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);
|
|
242 //const char *id = get_property("id", cur);
|
|
243 //int count = atoi(get_property("count", cur));
|
|
244
|
|
245 /* store float inpoint list */
|
|
246 for (int i = 0; cont != NULL; i++) {
|
|
247 cont = pickup_float(cont, src->u.array+i);
|
|
248 }
|
|
249
|
|
250 src->next = NULL;
|
|
251 addSource(list, src);
|
|
252 printf("id:%s count:%d cont:%s\n", id, count, cont);
|
|
253 }
|
|
254
|
|
255
|
|
256 void
|
|
257 get_points(xmlNodePtr cur, collada_state *s, TaskManager *manager){
|
|
258 char *pcont = (char*)xmlNodeGetContent(cur);
|
|
259 for (int i = 0;i < s->polylist_count;i++){
|
|
260 s->vcsum += s->vcount[i];
|
|
261 s->vmember = i;
|
|
262 }
|
|
263 s->limit = s->vcsum * 2;
|
|
264 if (s->texcoord_offset == 2){
|
|
265 s->limit = s->vcsum * 3;
|
|
266 }
|
|
267 s->pcount = new float[s->limit];
|
|
268 for (int i=0;i<s->limit;i++){
|
|
269 s->pcount[i] = 0;
|
|
270 }
|
|
271 for (int i=0; pcont != NULL; i++) {
|
|
272 pcont = pickup_float(pcont, s->pcount+i);
|
|
273 }
|
|
274 }
|
|
275 SceneGraph*
|
|
276 decode_points(collada_state *s, TaskManager *manager, SceneGraphPtr sg){
|
|
277 int *vertexp;
|
|
278 vertexp = new int[s->vcsum];
|
|
279 for (int i=0;i<s->vcsum;i++){
|
|
280 vertexp[i]=0;
|
|
281 }
|
|
282 /*
|
|
283 * vertex_tableだけはpolygonを作る際にvcountが4の場合重複する点が
|
|
284 * 出てくるのでサイズを2倍用意しておく
|
|
285 */
|
|
286 float *vertex_table;
|
|
287 float *normal_table;
|
|
288 float *texcoord_table;
|
|
289 vertex_table = new float[(s->vcsum)*2];
|
|
290 normal_table = new float[s->vcsum];
|
|
291 texcoord_table = new float[s->vcsum];
|
|
292 for (int i=0;i < s->vcsum;i++){
|
|
293 vertex_table[i] = 0;
|
|
294 normal_table[i] = 0;
|
|
295 texcoord_table[i] = 0;
|
|
296 }
|
|
297
|
|
298 /**
|
|
299 * s->vcsum と s->vertex_float->countの値が違うので大きい方をとりあえず使っておく
|
|
300 */
|
|
301
|
|
302 /* p separate vertex position and nomal position. */
|
|
303 if (s->texcoord_offset == 2){
|
|
304 for (int i=0,j=0; i < s->limit; i+=3,j++) {
|
|
305 vertexp[j] = (int)s->pcount[i];
|
|
306 normal_table[j] = s->normal_float->u.array[(int)s->pcount[i+1]];
|
|
307 texcoord_table[j] = s->texcoord_float->u.array[(int)s->pcount[i+2]];
|
|
308 }
|
|
309 } else{
|
|
310 for (int i=0,j=0; i < s->limit; i+=2,j++) {
|
|
311 vertexp[j] = (int)s->pcount[i];
|
|
312 normal_table[j] = s->normal_float->u.array[(int)s->pcount[i+1]];
|
|
313 }
|
|
314 }
|
|
315
|
|
316 /* make triangle */
|
|
317 int k=0,l=0;
|
|
318 for (int i=0;i<s->vmember;i++) {
|
|
319 if (s->vcount[i] == 4) {
|
|
320 vertex_table[k++] = s->vertex_float->u.array[vertexp[l]];
|
|
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+1]];
|
|
324 vertex_table[k++] = s->vertex_float->u.array[vertexp[l+2]];
|
|
325 vertex_table[k++] = s->vertex_float->u.array[vertexp[l+3]];
|
|
326 l+=4;
|
|
327 } else if (s->vcount[i]==3) {
|
|
328 vertex_table[k++] = s->vertex_float->u.array[vertexp[l++]];
|
|
329 vertex_table[k++] = s->vertex_float->u.array[vertexp[l++]];
|
|
330 vertex_table[k++] = s->vertex_float->u.array[vertexp[l++]];
|
|
331 }
|
|
332 }
|
|
333
|
|
334 /**
|
|
335 * (SceneGraph.cc)
|
|
336 * pickup_normal,pickup_coordinate,pickup_textureの処理
|
|
337 * vcsumは頂点の数,countは面の数
|
|
338 */
|
|
339 int count = s->vcsum / 3;
|
|
340 //polygonの作成
|
|
341 sg->pp_num = (count + MAX_SIZE_TRIANGLE - 1) / MAX_SIZE_TRIANGLE;
|
|
342 sg->pp = new PolygonPack[sg->pp_num];
|
|
343
|
|
344 for (int i = 0;i < sg->pp_num; i++ ){
|
|
345 PolygonPackPtr pp = sg->pp;
|
|
346 TrianglePackPtr tri = pp[i].tri;
|
|
347 // TrianglePack の size のチェック
|
|
348 int tri_size = (count < MAX_SIZE_TRIANGLE) ? count : MAX_SIZE_TRIANGLE ;
|
|
349 pp[i].info.size = tri_size;
|
|
350 /* default texture peste */
|
|
351 if (s->images_flag==0) {
|
1378
|
352 get_texture_image("/Users/YuSUGIMOTO/Cerium/Renderer/Test/xml_file/blend/images/ball.jpg", sg, (xmlNodePtr)NULL, manager);
|
1376
|
353 }
|
|
354 int k = 0;
|
|
355 int m = 0;
|
|
356 int n = 0;
|
|
357 for (int j = 0; j < tri_size; j++) {
|
|
358 tri[j].normal1.x = normal_table[k++];
|
|
359 tri[j].normal1.y = normal_table[k++];
|
|
360 tri[j].normal1.z = normal_table[k++];
|
|
361
|
|
362 tri[j].normal2.x = normal_table[k++];
|
|
363 tri[j].normal2.y = normal_table[k++];
|
|
364 tri[j].normal2.z = normal_table[k++];
|
|
365
|
|
366 tri[j].normal3.x = normal_table[k++];
|
|
367 tri[j].normal3.y = normal_table[k++];
|
|
368 tri[j].normal3.z = normal_table[k++];
|
|
369
|
|
370 tri[j].ver1.tex_x = texcoord_table[m++];
|
|
371 tri[j].ver1.tex_y = texcoord_table[m++];
|
|
372
|
|
373 tri[j].ver2.tex_x = texcoord_table[m++];
|
|
374 tri[j].ver2.tex_y = texcoord_table[m++];
|
|
375
|
|
376 tri[j].ver3.tex_x = texcoord_table[m++];
|
|
377 tri[j].ver3.tex_y = texcoord_table[m++];
|
|
378
|
|
379 tri[j].ver1.x = vertex_table[n++];
|
|
380 tri[j].ver1.y = vertex_table[n++];
|
|
381 tri[j].ver1.z = vertex_table[n++];
|
|
382
|
|
383 tri[j].ver2.x = vertex_table[n++];
|
|
384 tri[j].ver2.y = vertex_table[n++];
|
|
385 tri[j].ver2.z = vertex_table[n++];
|
|
386
|
|
387 tri[j].ver3.x = vertex_table[n++];
|
|
388 tri[j].ver3.y = vertex_table[n++];
|
|
389 tri[j].ver3.z = vertex_table[n++];
|
|
390
|
|
391 }
|
|
392
|
|
393 }
|
|
394 sg->c_xyz[0] = sg->c_xyz[1] = sg->c_xyz[2] = 0;
|
|
395
|
|
396 //int tex_id = 0;
|
|
397 //sgid_hash.sg_hash_regist(s->name, tex_id);
|
|
398
|
|
399 delete []vertexp;
|
|
400 delete []vertex_table;
|
|
401 delete []normal_table;
|
|
402 delete []texcoord_table;
|
|
403
|
|
404 /* got out of polylist */
|
|
405 s->polylist = 0;
|
|
406 return sg;
|
|
407 }
|
|
408
|
|
409 static void
|
|
410 xml_walk(xmlNodePtr cur, struct collada_state *s, LIST_P list,SceneGraphPtr sg, SceneGraphRoot *root)
|
|
411 {
|
|
412 int in_polylist=0;
|
1378
|
413 //printf("name = %s, child:%s\n", (char *)cur->name, (char *)cur->children);
|
|
414 //printf("s->polylist = %d\n",s->polylist);
|
1376
|
415 if (!xmlStrcmp(cur->name, (xmlChar*)"polylist")) {
|
|
416 s->polylist_count = atoi((char*)xmlGetProp(cur, (xmlChar*)"count"));
|
|
417 s->polylist=1;
|
|
418 in_polylist=1;
|
|
419 } else if (!xmlStrcmp(cur->name, (xmlChar*)"vertices")) {
|
|
420 s->vertices_id = xmlGetProp(cur, (xmlChar*)"id");
|
|
421 } else if (!xmlStrcmp(cur->name, (xmlChar*)"library_images")) {
|
1378
|
422 s->library_images=1;
|
|
423 //library_images is wrote at texture image name. only use one image file
|
1376
|
424 } else if (s->library_images && !xmlStrcmp(cur->name, (xmlChar*)"init_from")) {
|
|
425 s->tex_picname = (char*)xmlGetProp(cur, (xmlChar*)"init_from");
|
|
426 get_texture_image(s->tex_picname, sg, cur , root->tmanager);
|
|
427 printf("------------------%s",s->tex_picname);
|
|
428 s->library_images=0;
|
|
429 s->images_flag=1;
|
|
430 } else if (!s->polylist && !xmlStrcmp(cur->name, (xmlChar*)"input")) {
|
|
431 char *semantic = (char*)xmlGetProp(cur, (xmlChar*)"semantic");
|
|
432 if (!xmlStrcmp((xmlChar*)semantic, (xmlChar*)"POSITION")) {
|
|
433 s->vertices_src = (char*)xmlGetProp(cur, (xmlChar*)"source");
|
|
434 }
|
|
435 } else if (s->polylist && !xmlStrcmp(cur->name, (xmlChar*)"input")) {
|
|
436 char *semantic = (char*)xmlGetProp(cur, (xmlChar*)"semantic");
|
|
437 if (!xmlStrcmp((xmlChar*)semantic, (xmlChar*)"VERTEX")) {
|
|
438 s->vertex_src = (char*)xmlGetProp(cur, (xmlChar*)"source");
|
|
439 s->vertex_float = most_match(s->vertices_src+1, list);
|
|
440 } else if (!xmlStrcmp((xmlChar*)semantic, (xmlChar*)"NORMAL")) {
|
|
441 s->normal_src = (char*)xmlGetProp(cur, (xmlChar*)"source");
|
|
442 s->normal_offset = atoi((char*)xmlGetProp(cur, (xmlChar*)"offset"));
|
|
443 s->normal_float = most_match(s->normal_src+1, list);
|
|
444 } else if (!xmlStrcmp((xmlChar*)semantic, (xmlChar*)"TEXCOORD")) {
|
|
445 s->texcoord_src = (char*)xmlGetProp(cur, (xmlChar*)"source");
|
|
446 s->texcoord_offset = atoi((char*)xmlGetProp(cur, (xmlChar*)"offset"));
|
|
447 s->texcoord_float = most_match(s->texcoord_src+1, list);
|
|
448 }
|
|
449 } else if (!xmlStrcmp(cur->name, (xmlChar*)"vcount")) {
|
|
450 char *vcont = (char*)xmlNodeGetContent(cur);
|
|
451 s->vcount = new float[s->polylist_count];
|
|
452 for (int i=0; vcont!=NULL; i++) {
|
|
453 /* store vcount list */
|
|
454 vcont = pickup_float(vcont, s->vcount+i);
|
|
455 }
|
|
456 } else if (!xmlStrcmp(cur->name, (xmlChar*)"p")) {
|
|
457 get_points(cur,s,root->tmanager);
|
|
458 in_polylist = 0;
|
|
459 } else if (!xmlStrcmp(cur->name, (xmlChar*)"float_array")) {
|
|
460 decode_float_array(cur,list);
|
|
461 } else if (!xmlStrcmp(cur->name, (xmlChar*)"node" )) {
|
|
462 s->name = (char*)xmlGetProp(cur, (xmlChar*)"id");
|
|
463 }
|
|
464 for (cur=cur->children; cur; cur=cur->next){
|
|
465 xml_walk(cur,s,list,sg,root);
|
|
466 }
|
|
467 }
|
|
468 void
|
|
469 init_list(LIST_P list) {
|
|
470 list->first = NULL;
|
|
471 list->end = NULL;
|
|
472 }
|
|
473
|
|
474
|
|
475 void
|
|
476 SceneGraphRoot::createFromCOLLADAfile(TaskManager *manager, const char *xmlColladafile)
|
|
477 {
|
|
478 /*make parse dom*/
|
|
479 xmlDocPtr doc;
|
|
480 xmlNodePtr cur;
|
|
481 //,cur_images,cur_effects,cur_geometries,cur_visual_scenes;
|
|
482 //SceneGraphPtr tmp;
|
|
483
|
|
484 doc = xmlParseFile(xmlColladafile);
|
|
485 cur = xmlDocGetRootElement(doc);
|
|
486
|
|
487 if (xmlStrcmp(cur->name, (xmlChar*)"COLLADA")){
|
|
488 return ;
|
|
489 }
|
|
490
|
|
491 /* node analyze */
|
|
492 struct collada_state s;
|
|
493 SceneGraphPtr sg = new SceneGraph(manager);
|
|
494 for (cur=cur->children; cur; cur=cur->next){
|
|
495 LIST list;
|
|
496 init_list(&list);
|
|
497 xml_walk(cur,&s,&list,sg,this);
|
|
498 }
|
|
499 registSceneGraph(decode_points(&s,manager,sg));
|
|
500 xmlFreeDoc(doc);
|
|
501 }
|