Mercurial > hg > Members > e085722 > Cerium
diff Renderer/Engine/SceneGraph.cc @ 0:04e28d8d3c6f
first commit
author | Daiki KINJYO <e085722@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 08 Nov 2010 01:23:25 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Renderer/Engine/SceneGraph.cc Mon Nov 08 01:23:25 2010 +0900 @@ -0,0 +1,808 @@ +#include <iostream> +#include <SDL.h> +#include <SDL_opengl.h> +#include <SDL_image.h> +#include <libxml/parser.h> +#include "SceneGraph.h" +#include "xml.h" +#include "sys.h" +#include "TextureHash.h" +#include "texture.h" +#include "TaskManager.h" + +using namespace std; + +SceneGraphPtr scene_graph = NULL; +SceneGraphPtr scene_graph_viewer = NULL; + +static TextureHash texture_hash; +texture_list list[TABLE_SIZE]; + + +extern int decode(char *cont, FILE *outfile); + +static void +no_move(SceneGraphPtr self, void *sgroot_, int screen_w, int screen_h) {} + +static void +no_collision(SceneGraphPtr self, void *sgroot_, int screen_w, int screen_h, + SceneGraphPtr tree) {} + +/** + * 事前に計算したテクスチャの最大縮小率 scale まで、 + * テクスチャを 1/2 縮小していく。 + * このとき、テクスチャは TEXTURE_SPLIT_PIXELx2 のブロック (Tile) で分割し、 + * これらを連続したメモリ領域に格納していく。 + * 以下の (1), (2), (3) を Tapestry と呼ぶ + * + * 例 scale = 4 の場合 + * + * Tapestry(1) 1/1 + * +---+---+---+---+ + * | 0 | 1 | 2 | 3 | + * +---+---+---+---+ + * | 4 | 5 | 6 | 7 | (2) 1/2 + * +---+---+---+---+ +---+---+ + * | 8 | 9 | 10| 11| | 16| 17| (3) 1/4 + * +---+---+---+---+ +---+---+ +---+ + * | 12| 13| 14| 15| | 18| 19| | 20| + * +---+---+---+---+ +---+---+ +---| + * + * (1) (2) (3) + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * | * | * | 14| 15| 16| 17| 18| 19| 20| + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * + * @param[in] tex_w Width of orignal texture + * @param[in] tex_h Height of orignal texture + * @param[in] tex_src Original texture + * @param[in] all_pixel_num Tapestry の合計 pixel 数 + * @param[in] scale テクスチャの最大縮小率 (= 2^n) + * @return (1) のアドレス + */ +static uint32* +makeTapestry(TaskManager *manager, int tex_w, int tex_h, uint32 *tex_src, + int all_pixel_num, int scale_cnt) +{ + + int t = 0; + int diff = TEXTURE_SPLIT_PIXEL; + int p_diff = 1; + + uint32 *tex_dest = (uint32*)manager->allocate(sizeof(int)*all_pixel_num); + + while (scale_cnt) { + for (int y = 0; y < tex_h; y += diff) { + for (int x = 0; x < tex_w; x += diff) { + for (int j = 0; j < diff; j += p_diff) { + for (int i = 0; i < diff; i += p_diff) { + tex_dest[t++] + = tex_src[(x+i) + tex_w*(y+j)]; + } + } + } + } + + diff <<= 1; + p_diff <<= 1; + scale_cnt >>= 1; + } + + return tex_dest; +} + + +/** + * 何の情報も持ってない SceneGraph の生成 + * 今のところ、とりあえず木構造の繋がりに使うぐらい + */ +SceneGraph::SceneGraph() +{ + init(); + finalize = &SceneGraph::finalize_copy; + + this->name = "NULLPO"; +} + +/** + * orig のコピーとして SceneGraph を生成する + */ +SceneGraph::SceneGraph(SceneGraphPtr orig) +{ + + init(); + memcpy(this, orig, sizeof(SceneGraph)); + + // コピーしない + //flag_remove = 0; + //flag_drawable = 1; + next = NULL; + prev = NULL; + last = NULL; + + parent = NULL; + brother = NULL; + children = NULL; + lastChild = NULL; + + finalize = &SceneGraph::finalize_copy; + + + frame = 0; +} + + +/* construct polygon from xmlNode. */ +SceneGraph::SceneGraph(TaskManager *manager, xmlNodePtr surface) +{ + init(); + + size = atoi((char *)xmlGetProp(surface,(xmlChar *)"size")); + name = (char *)xmlGetProp(surface,(xmlChar *)"name"); + parent_name = (char *)xmlGetProp(surface,(xmlChar *)"parent"); + //texture_info = (texture_list_ptr)manager->allocate(sizeof(texture_list)); + //data = new float[size*3*3]; + + for (int i = 0; i < 16; i++) { + matrix[i] = 0; + real_matrix[i] = 0; + } + +#if SPE_CREATE_POLYGON_CHECK + + for (int i = 0; i < 16; i++) { + printf("%f\n",matrix[i]); + printf("r %f\n",real_matrix[i]); + } + +#endif + + coord_xyz = (float*)manager->allocate(sizeof(float)*size*3); + coord_tex = (float*)manager->allocate(sizeof(float)*size*3); + normal = (float*)manager->allocate(sizeof(float)*size*3); + + coord_pack_size = sizeof(float)*8*size*3; // coord_pack_vertex size is 32byte. vertex num 3. + coord_pack = (float*)manager->allocate(coord_pack_size); + + get_data(manager, surface->children); + + finalize = &SceneGraph::finalize_original; +} + +void +SceneGraph::init() +{ + next = NULL; + prev = NULL; + last = NULL; + + parent = NULL; + brother = NULL; + children = NULL; + lastChild = NULL; + + stack_xyz[0] = 0.0f; + stack_xyz[2] = 0.0f; + stack_xyz[1] = 0.0f; + stack_angle[0] = 0.0f; + stack_angle[1] = 0.0f; + stack_angle[2] = 0.0f; + + size = 0; + //data = NULL; + +#if SPE_CREATE_POLYGON + + //tri_pack = NULL; + //sg_matrix = NULL; + //matrix = NULL; + //real_matrix = NULL; + //texture_info = NULL; + +#else + + coord_xyz = NULL; + normal = NULL; + coord_tex = NULL; + +#endif + + texture_id = -1; + move = no_move; + collision = no_collision; + + flag_remove = 0; + flag_drawable = 1; + sgid = -1; + gid = -1; + + frame = 0; +} + +SceneGraph::~SceneGraph() +{ + (this->*finalize)(); +} + +/** + * xml ファイルから生成されたオリジナル SceneGraph なので + * polygon data を削除 + */ +void +SceneGraph::finalize_original() +{ + //delete [] data; + +#if SPE_CREATE_POLYGON + + free(coord_pack); + free(coord_xyz); + free(coord_tex); + free(normal); + +#else + + free(coord_xyz); + free(coord_tex); + free(normal); + +#endif + +} + +/** + * SceneGraph ID から生成された、コピー SceneGraph なので + * polygon data は削除しない。オリジナルの方で削除する。 + */ +void +SceneGraph::finalize_copy() +{ +} + + +/** + * add Children + * 親の登録と、brother のリストへ加える + * + * @param child new child + */ +SceneGraphPtr +SceneGraph::addChild(SceneGraphPtr child) +{ + /* childrenのリストの最後に加える (brother として)*/ + if (this->lastChild != NULL) { + SceneGraphPtr last = this->lastChild; + last->brother = child; + //child->parent = this; + //return child; + } + + this->lastChild = child; + + if (this->children == NULL) { + this->children = child; + } + + child->parent = this; + + return child; +} + + +/** + * add Brother + * addChild() でも brother の操作をしないといけないので、そっちに回す + * + * @param bro new Brother + */ +SceneGraphPtr +SceneGraph::addBrother(SceneGraphPtr bro) +{ + if (this->parent) { + parent->addChild(bro); + } else { + fprintf(stderr, "error : SceneGraph::%s : %s doesn't have parent\n", + __FUNCTION__, this->name); + } + + return bro; +} + +/* thisの子や子孫にnameのものが存在すればそいつを返す なければNULL. */ +SceneGraphPtr +SceneGraph::searchSceneGraph(const char *name) +{ + SceneGraphPtr tmp; + SceneGraphPtr result; + + /* 本人か */ + if( 0==strcmp(this->name, name) ) return this; + + /* 子供から再帰的に探す */ + for(tmp = this->children; tmp; tmp = tmp->next) { + if ((result=tmp->searchSceneGraph(name)) != NULL) + return result; + } + + /* 無かったら NULL. */ + return NULL; +} + +void +SceneGraph::tree_check() +{ + SceneGraphPtr t = this; + + while(t) + { + cout << "my_name : " << t->name << endl; + if(t->children != NULL) + { + cout << "--move children : " << t->children->name << endl; + t = t->children; + } + else if(t->brother != NULL) + { + cout << "--move brother : " << t->brother->name << endl; + t = t->brother; + } + else + { + while(t) + { + if(t->brother != NULL) + { + cout << "--move brother : " << t->brother->name << endl; + t = t->brother; + break; + } + else + { + if(t->parent) + { + cout << "--move parent : " << t->parent->name << endl; + } + t = t->parent; + } + } + } + } +} + + +void +SceneGraph::print_member() +{ + cout << "size = " << size << endl; + cout << "name = " << name << endl; + cout << "parent_name = " << parent_name << endl; + + if (parent != NULL) { + cout << "parent->name = " << parent->name << endl; + } + + if (children != NULL) { + cout << "children->name = " << children->name << endl; + } +} + + +/* + * surface nodeからポリゴンの情報を読み出す 再帰しない + */ +void +SceneGraph::get_data(TaskManager *manager, xmlNodePtr cur) +{ + //char *image_name; + + for(;cur;cur=cur->next) + { + if(!xmlStrcmp(cur->name,(xmlChar*)"coordinate")) + { + char *cont = (char *)xmlNodeGetContent(cur); + pickup_coordinate(cont); + } + else if(!xmlStrcmp(cur->name,(xmlChar*)"normal")) + { + char *cont = (char *)xmlNodeGetContent(cur); + pickup_normal(cont); + } + else if(!xmlStrcmp(cur->name,(xmlChar*)"model")) + { + char *cont = (char *)xmlNodeGetContent(cur); + pickup_model(cont); + } + else if(!xmlStrcmp(cur->name,(xmlChar*)"texture")) + { + char *cont = (char *)xmlNodeGetContent(cur); + pickup_texture(cont); + } + else if(!xmlStrcmp(cur->name,(xmlChar*)"imageflag")) + { + int id; + char *filename = (char *)xmlGetProp(cur, (xmlChar *)"name"); + texture_hash.hash_regist(filename, id); + } + else if(!xmlStrcmp(cur->name,(xmlChar*)"image")) + { + get_image(manager, cur); + } + } +} + +SDL_Surface* +SceneGraph::load_decode_image(char *image_name, xmlNodePtr cur) +{ + int fd = mkstemp(image_name); + FILE *outfile = fdopen(fd, "wb"); + + if (NULL == outfile) { + cout << "error open file\n"; + return 0; + } + + char *cont = (char *)xmlNodeGetContent(cur); + //decode(cont, image_name); + decode(cont, outfile); + fclose(outfile); + + +/** + * image を 32bit(RGBA) に変換する + */ + SDL_Surface *texture_image = IMG_Load(image_name); + if (!texture_image) return 0; + SDL_Surface *tmpImage + = SDL_CreateRGBSurface(SDL_SWSURFACE, 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; + } + + // this->gl_tex = SDL_GL_LoadTexture(texture_image); + return texture_image; +} + +int +SceneGraph::makeTapestries(TaskManager *manager, SDL_Surface *texture_image, int id) { + uint32 *tapestry; + int scale = 1; + int tex_w = texture_image->w; + int tex_h = texture_image->h; + int all_pixel_num = 0; + + /** + * テクスチャの w or h が 8 pixel で分割できる間、 + * 1/2 の縮小画像を作る。 + * ここでは、最大の scale (1/scale) を見つける + * + * (ex) + * (128,128) => 64,64 : 32,32: 16,16 : 8,8 + * scale = 16 + * (128, 64) => 64,32 : 32,16: 16,8 + * scale = 8 + */ + while (tex_w % TEXTURE_SPLIT_PIXEL == 0 && + tex_h % TEXTURE_SPLIT_PIXEL == 0) { + all_pixel_num += tex_w*tex_h; + tex_w >>= 1; /* tex_w /= 2 */ + tex_h >>= 1; + scale <<= 1; /* scale *= 2 */ + } + + scale >>= 1; + + tapestry = makeTapestry(manager, texture_image->w, texture_image->h, + (uint32*)texture_image->pixels, + all_pixel_num, scale); + + list[id].t_w = texture_image->w; + list[id].t_h = texture_image->h; + list[id].pixels_orig = (Uint32*)texture_image->pixels; + list[id].pixels = tapestry; + list[id].scale_max = scale; + list[id].texture_image = texture_image; + + return id; + } + +void +SceneGraph::get_image(TaskManager *manager, xmlNodePtr cur) +{ + char image_name[20] = "/tmp/image_XXXXXX"; + char *filename = (char *)xmlGetProp(cur, (xmlChar *)"name"); + + if (filename == NULL || filename[0] == 0) { + return; + } + + /** + * image_name を既に Load していれば何もしない + */ + int tex_id; + if (!texture_hash.hash_regist(filename, tex_id)) { + + SDL_Surface *texture_image = load_decode_image(image_name, cur); + if (texture_image==0) { + printf("Can't load image %s\n",filename); + exit(0); + } + + texture_id = makeTapestries(manager, texture_image, tex_id); + + if (unlink(image_name)) { + cout << "unlink error\n"; + } + } else { + /** + * 以前に Load されている Texture を共用 + */ + texture_id = tex_id; + } + + // こんなことすると list[] のいみあるのかなーと + // 微妙に思う、自分で書き換えた感想 by gongo + texture_info.t_w = list[texture_id].t_w; + texture_info.t_h = list[texture_id].t_h;; + texture_info.pixels_orig = list[texture_id].pixels_orig; + texture_info.pixels = list[texture_id].pixels; + texture_info.scale_max = list[texture_id].scale_max; + texture_info.texture_image = list[texture_id].texture_image; + +} + + +void +SceneGraph::delete_data() +{ + SceneGraphPtr n = this->next, m; + + //n = this; + //delete [] n->data; + + if (next) { + while (n) { + m = n->next; + delete n; + n = m; + } + } +} + +/* move_func 実行 sgroot 渡す */ +void +SceneGraph::move_execute(int w, int h) +{ + (*move)(this, this->sgroot, w, h); +} + +void +SceneGraph::collision_check(int w, int h, SceneGraphPtr tree) +{ + (*collision)(this, this->sgroot, w, h, tree); +} + +void +SceneGraph::create_sg_execute() +{ + (*create_sg)(this->sgroot, property, update_property); +} + + +void +SceneGraph::set_move_collision(move_func new_move, + collision_func new_collision) +{ + this->move = new_move; + this->collision = new_collision; +} + + +void +SceneGraph::set_move_collision(move_func new_move, + collision_func new_collision, void *sgroot_) +{ + this->move = new_move; + this->collision = new_collision; + // add + this->sgroot = sgroot_; +} + +void +SceneGraph::set_move_collision(move_func new_move, + collision_func new_collision, create_sg_func new_create_sg) +{ + this->move = new_move; + this->collision = new_collision; + this->create_sg = new_create_sg; +} + +void +SceneGraph::add_next(SceneGraphPtr next) +{ + /* next のリストの最後に加える */ + if (this->next != NULL) { + SceneGraphPtr tmp = this->last; + tmp->next = next; + } else { + this->next = next; + } + + this->last = next; +} + +/** + * SceneGraph の clone + * @return clone SceneGraph + */ +SceneGraphPtr +SceneGraph::clone() { + SceneGraphPtr p = new SceneGraph(this); + return p; +} + +/** + * SceneGraph の clone + * 予め allocate されてる領域への placement new を行う + * + * @param buf clone 領域 + * @return clone SceneGraph + */ +SceneGraphPtr +SceneGraph::clone(void *buf) { + SceneGraphPtr p = new(buf) SceneGraph(this); + return p; +} + +void +SceneGraph::remove() +{ + this->flag_remove = 1; +} + +/** + * tree から node を削除する + * + * @param tree SceneGraphTree + * @return node削除後の SceneGraphTree + */ +SceneGraphPtr +SceneGraph::realRemoveFromTree(SceneGraphPtr tree) +{ + SceneGraphPtr node = this; + SceneGraphPtr parent = node->parent; + SceneGraphPtr ret = tree; + + if (parent) { + SceneGraphPtr brother = parent->children; + SceneGraphPtr p, p1 = NULL; + + p = brother; + if (p) { + if (p == node) { + parent->children = NULL; + parent->lastChild = NULL; + } else { + p1 = p->brother; + + while (p1 && p1 != node) { + p1 = p1->brother; + p = p->brother; + } + + if (p1) { + p->brother = p1->brother; + + // node が最後尾なら、lastChild を変更 + if (parent->lastChild == p1) { + parent->lastChild = p; + } + } else { + // Can't find remove node + } + } + } + } else { + // 親が居ない = tree root なので + // NULL を返す + ret = NULL; + } + + return ret; +} + +/** + * list から node を削除する + * + * @param list SceneGraphList + * @return node削除後の SceneGraphList + */ +SceneGraphPtr +SceneGraph::realRemoveFromList(SceneGraphPtr list) +{ + SceneGraphPtr node = this; + SceneGraphPtr prev = node->prev; + SceneGraphPtr next = node->next; + SceneGraphPtr ret = list; + + if (prev) { + prev->next = next; + } else { + ret = next; + } + + if (next) { + next->prev = prev; + } + + return ret; +} + +int +SceneGraph::isRemoved() +{ + return flag_remove; +} + +/** + * 平行移動 + * + * @param x Ttranslate in the x direction + * @param y Ttranslate in the y direction + * @param z Ttranslate in the z direction + */ +void +SceneGraph::translate(float x, float y, float z) +{ + this->xyz[0] = x; + this->xyz[1] = y; + this->xyz[2] = z; +} + +/** + * x 軸方向への平行移動 + * + * @param x Ttranslate in the x direction + */ +void +SceneGraph::translateX(float x) +{ + this->xyz[0] = x; +} + +/** + * y 軸方向への平行移動 + * + * @param y Ttranslate in the y direction + */ +void +SceneGraph::translateY(float y) +{ + this->xyz[1] = y; +} + +/** + * z 軸方向への平行移動 + * + * @param z Ttranslate in the z direction + */ +void +SceneGraph::translateZ(float z) +{ + this->xyz[2] = z; +} + +/* end */