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 */