view Renderer/Engine/SceneGraph.cc @ 2041:363b7c401c79 draft

Make Rendefing Engine
author Shin,ichi Uehara
date Mon, 23 Mar 2015 17:47:12 +0900
parents 6748a09c63cb
children cf10def20fb7
line wrap: on
line source

#include <iostream>
#include <SDL.h>
#include <SDL_opengl.h>
#include <SDL_image.h>
#include <libxml/parser.h>
#include <string.h>
#include "SceneGraph.h"
#include "xml.h"
#include "matrix_calc.h"
#include "TextureHash.h"
#include "texture.h"
#include "TaskManager.h"
#include "polygon_pack.h"
#include <ft2build.h>
//#include <freetype/freetype.h>
#include <freetype.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) のアドレス
 */


uint32 white[256] __attribute__((aligned(16)));

static uint32*
makeTapestry(TaskManager *manager, uint32 tex_w, uint32 tex_h, uint32 *tex_src,
             int all_pixel_num, int scale_cnt)
{
    if (tex_w==0 && tex_h==0) {
	// non texture case
	uint32 pattern = SDL_BYTEORDER == SDL_LIL_ENDIAN? 0x00ffffff : 0xffffff00; /* OpenGL RGBA masks */
	if (white[0]!=pattern)  { // dumb!
#if 1
            for(int i=0;i<256;i++)
               white[i] = pattern;
#else
	    memset_pattern4(white,&pattern,256);
#endif
        }
	return white;
    }

    uint32 t = 0;
    uint32 diff = TEXTURE_SPLIT_PIXEL;
    uint32 p_diff = 1;

    uint32 *tex_dest = (uint32*)manager->allocate(sizeof(int)*all_pixel_num);
    // uint32 *tex_src_max = (uint32*)( tex_src + tex_h*tex_w);

    // uint32 alpha =  SDL_BYTEORDER == SDL_LIL_ENDIAN? 0xff000000 : 0xff; /* OpenGL RGBA masks */
    uint32 alpha =  tex_src[0];

    while (scale_cnt) {
	// we should use average, except clear one
        for (uint32 y = 0; y < align(tex_h,diff); y += diff) {
            for (uint32 x = 0; x < align(tex_w,diff); x += diff) {
                for (uint32 j = 0; j < diff; j += p_diff) {
                    for (uint32 i = 0; i < diff; i += p_diff) {
                        tex_dest[t++] = 
			    (x+i<tex_w && y+j<tex_h) ? tex_src[(x+i) + tex_w*(y+j)]: alpha;
                    }
                }
            }
        }

        diff <<= 1; p_diff <<= 1;
        scale_cnt >>= 1;
    }

    return tex_dest;
}


/**
 * 何の情報も持ってない SceneGraph の生成
 * 今のところ、とりあえず木構造の繋がりに使うぐらい
 */
SceneGraph::SceneGraph(TaskManager *manager)
{

    init();
    allocate_init(manager);
    texture_info->texture_id = -1;

    finalize = &SceneGraph::finalize_copy;

    this->name = "NULLPO";
 
}

/**
 * orig のコピーとして SceneGraph を生成する
 */
SceneGraph::SceneGraph( TaskManager *manager, SceneGraphPtr orig)
{

    init();

    memcpy(this, orig, sizeof(SceneGraph));

    allocate_init(manager);

    for (int i = 0; i < 16; i++) {
      matrix[i] = orig->matrix[i];
    }

    memcpy(texture_info, orig->texture_info, sizeof(texture_list));

    // コピーしない
    //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();
    allocate_init(manager);
    texture_info->texture_id = -1;
    
    //size : 頂点の数かな
    size = atoi((char *)xmlGetProp(surface,(xmlChar *)"size"));
    name = (char *)xmlGetProp(surface,(xmlChar *)"name");
    parent_name = (char *)xmlGetProp(surface,(xmlChar *)"parent");

    if (size % 3 != 0) {
      printf("vertex size is error. size %% 3 = %lld\n", size % 3);
    }

    /*
     * MAX_SIZE_TRIANGLE:128
     */

    if (size > 0) {
 
      /* 
       * size/3 : 三角形の数
       * MAX_SIZE_TRIANGLE : 128
       * polygon の数から、PolygonPackの数を決定する
       */
      
      pp_num = (size/3 + MAX_SIZE_TRIANGLE - 1) / MAX_SIZE_TRIANGLE;
      pp = (PolygonPack*)manager->allocate(sizeof(PolygonPack)*pp_num);
    } else {
      pp_num = 0;
      pp = NULL;
    }

    get_data(manager, surface->children);

    finalize = &SceneGraph::finalize_original;

}


SceneGraph::SceneGraph(TaskManager *manager,const char *font,int pixels,Uint32 color,const char *string_name) {

    init();
    allocate_init(manager);
    texture_info->texture_id = -1;

    for (int i = 0; i < 16; i++) {
      matrix[i]      = 0;
    }
    for (int i = 0; i < 4; i++) {
      matrix[i*4+i]      = 1;
    }
    
    //size : 頂点の数かな
    size = 6;
    parent_name = NULL;
    name = string_name;

    if (size % 3 != 0) {
      printf("vertex size is error. size %% 3 = %lld\n", size % 3);
    }

    if (size > 0) {
      pp_num = (size/3 + MAX_SIZE_TRIANGLE - 1) / MAX_SIZE_TRIANGLE;
      pp = (PolygonPack*)manager->allocate(sizeof(PolygonPack)*pp_num);
    } else {
      pp_num = 0;
      pp = NULL;
    }

    create_font_data(manager, font, pixels, color, string_name);

    finalize = &SceneGraph::finalize_original;
}

void
SceneGraph::create_font_data(TaskManager *manager,const char *font ,int pixels, Uint32 color, const char *string_name)
{
            //font_coordinate(pixels/2,pixels);
 	    font_normal();
            font_model();
            //font_texture();

            get_font_image(manager, font, pixels, color, string_name);
}

void
SceneGraph::get_font_image(TaskManager *manager,const char *font ,int pixels ,Uint32 color, const char *string_name)
{
  int tex_id;
  if (texture_hash.hash_regist(string_name, tex_id)) {
    SDL_Surface *texture_image = load_font_image(font,pixels,color,string_name);
    if(!texture_image){
      printf("Can't load image %s\n",string_name);
      exit(0);
    }
    texture_info->texture_id = makeTapestries(manager, texture_image,tex_id);
    printf("%d\n",texture_info->texture_id);
    tex_id = texture_info->texture_id;

  } else {
    texture_info->texture_id = tex_id;
  }

  texture_info->t_w = list[tex_id].t_w;
  texture_info->t_h = list[tex_id].t_h;
  texture_info->pixels_orig = list[tex_id].pixels_orig;
  texture_info->pixels = list[tex_id].pixels;
  texture_info->scale_max = list[tex_id].scale_max;
  texture_info->texture_image = list[tex_id].texture_image;
}

SDL_Surface*
SceneGraph::load_font_image(const char *font ,int pixel,Uint32 color , const char *string_name)
{
  //printf("laod_font_iamge");
  FT_Library library;
  FT_Error err;
  err = FT_Init_FreeType(&library);
  if(err){
    exit(1);
  }
  FT_Face face;
  err = FT_New_Face(library,font,0,&face);//font:フォントファイルのパス
  if(err){
    exit(1);
  }
  
  err = FT_Set_Pixel_Sizes(face,pixel,pixel);
  if(err){
    exit(1);
  }

  u_int32_t changecode[256] = {0};

  conv(string_name+5,strlen(string_name+5),changecode);

  unsigned int characode = changecode[0];

  err = FT_Load_Char(face,characode,0);
  if(err){
    exit(1);
  }
    
  err = FT_Render_Glyph(face->glyph,FT_RENDER_MODE_MONO);
  if(err){
    exit(1);
  }

  FT_Bitmap *bm = &face->glyph->bitmap;

  //baseline計算 y_ppem(nominal height) - bitmap_top(topからのbaseline)
  float baseline = face->size->metrics.y_ppem - face->glyph->bitmap_top;
  
  float row =  1;
  float width = 1;

  font_coordinate(baseline,face->glyph->bitmap.rows,face->glyph->bitmap.width);
  this->seq = face->glyph->bitmap.width;
  font_texture(row,width);

  int index = 0;
  Uint32 *pixels = (Uint32*)malloc(bm->rows*bm->pitch*8*4);

  for (int row = 0; row < bm->rows; row ++) {
      for (int col = 0; col < bm->pitch; col ++) {
          int c = bm->buffer[bm->pitch * row + col];
          for (int bit = 7; bit >= 0; bit --) {

              if (((c >> bit) & 1) == 0) {
		//printf("  ");
                  pixels[index++] = 0x0000000;
              } else {
		//printf("##");
                  //pixels[index++] = 0x00ffffff;
		  pixels[index++] = color;

              }

          }
      }

  }

  SDL_Surface *texture_image = SDL_CreateRGBSurfaceFrom(pixels, bm->pitch*8, bm->rows, 
                                                        32, bm->pitch*8*4, redMask,
                                                        greenMask, blueMask, alphaMask);



  if (!texture_image) {
    printf("error\n");
    return 0;
  }
  SDL_Surface *tmpImage
    = SDL_CreateRGBSurface(SDL_HWSURFACE, texture_image->w,
			   texture_image->h, 32, redMask,
			   greenMask, blueMask, alphaMask);


  SDL_Surface *converted;
  converted = SDL_ConvertSurface(texture_image, tmpImage->format,
				 SDL_HWSURFACE);
  if (converted != NULL) {
    SDL_FreeSurface(texture_image);
    texture_image = converted;
  }

  return texture_image;
}

void
SceneGraph::conv(const char *str, int length, u_int32_t *out) {
  int oindex = 0;
  int i = 0;
  while (i < length) {
    out[oindex] = str[i++] & 0xff;
    int len = 0;
    u_int32_t mask;
    for (mask = 0x80; out[oindex] & mask; mask >>= 1) {
      out[oindex] -= mask;
      len++;
    }
    int j;
    for (j = 1; j < len; j++)
      out[oindex] = (out[oindex] << 6) | (str[i++] & 0x3f);
    oindex++;
  }
}

/*文字のSceneGraphを生成する*/

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;
    pp_num = 0;

    //data = NULL;
   
    move = no_move;
    collision = no_collision;

    flag_remove = 0;
    flag_drawable = 1;
    sgid = -1;
    gid = -1;

    frame = 0;

}

// spe に渡すために 16アラインメント に allocate をする
void
SceneGraph::allocate_init(TaskManager *manager)
{
   matrix = (float*)manager->allocate(sizeof(float)*16);
   out_matrix = (float*)manager->allocate(sizeof(float)*16);
   texture_info = (texture_list*)manager->allocate(sizeof(texture_list));

    for (int i = 0; i < 16; i++) {
      matrix[i]      = 0;
      out_matrix[i]      = 0;
    }
    for (int i = 0; i < 4; i++) {
      matrix[i*4+i]      = 1;
      out_matrix[i*4+i]      = 1;
    }
}


SceneGraph::~SceneGraph()
{
    (this->*finalize)();
}

/**
 * xml ファイルから生成されたオリジナル SceneGraph なので
 * polygon data を削除
 */
void
SceneGraph::finalize_original()
{
    //delete [] data;

    free(pp);
    free(matrix);
    free(texture_info);

}

/**
 * SceneGraph ID から生成された、コピー SceneGraph なので
 * polygon data は削除しない。オリジナルの方で削除する。
 */
void
SceneGraph::finalize_copy()
{

    free(matrix);
    free(texture_info);
}


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


void Polygon::pickup_coordinate(char *cont)
{

    // size は頂点の数, count は面の数
    char *tmp_cont = cont;
    int count = size / 3;

    for (int i = 0; i < pp_num; i++) {

      TrianglePackPtr tri =  pp[i].tri;
      // TrianglePack の size のチェック
      
      int tri_size = (count < MAX_SIZE_TRIANGLE) ? count : MAX_SIZE_TRIANGLE ;
      
      //それを構造体に登録
      pp[i].info.size = tri_size;
      

      for (int j = 0; j < tri_size; j++) {

	tmp_cont = pickup_float(tmp_cont, &(tri[j].ver1.x));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].ver1.y));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].ver1.z));

	tmp_cont = pickup_float(tmp_cont, &(tri[j].ver2.x));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].ver2.y));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].ver2.z));

	tmp_cont = pickup_float(tmp_cont, &(tri[j].ver3.x));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].ver3.y));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].ver3.z));

	if (tmp_cont == NULL)
	  {
            cout << "Analyzing obj data failed coordinate\n";
	  }

	count -= 1;
	
      }
          
    }

    if (count != 0) {
          printf("miss pickup_coordinate size. diff size = %d\n", count);
    }

}

void Polygon::pickup_normal(char *cont)
{


    // size は頂点の数, count は面の数
    char *tmp_cont = cont;
    int count = size / 3;

    for (int i = 0; i < pp_num; i++) {

      TrianglePackPtr tri =  pp[i].tri;
      // TrianglePack の size のチェック
      int tri_size = (count < MAX_SIZE_TRIANGLE) ? count : MAX_SIZE_TRIANGLE ;
      pp[i].info.size = tri_size;

      for (int j = 0; j < tri_size; j++) {

	tmp_cont = pickup_float(tmp_cont, &(tri[j].normal1.x));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].normal1.y));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].normal1.z));

	tmp_cont = pickup_float(tmp_cont, &(tri[j].normal2.x));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].normal2.y));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].normal2.z));

	tmp_cont = pickup_float(tmp_cont, &(tri[j].normal3.x));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].normal3.y));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].normal3.z));


	if (tmp_cont == NULL)
	  {
            cout << "Analyzing obj data failed coordinate\n";
	  }

	count -= 1;
	
      }
      
    
    }

    if (count != 0) {
          printf("miss pickup_normal size. diff size = %d\n", count);
    }

}

void Polygon::pickup_model(char *cont)
{
    cont = pickup_float(cont,c_xyz);
    cont = pickup_float(cont,c_xyz+1);
    cont = pickup_float(cont,c_xyz+2);

    if (cont == NULL)
    {
        cout << "Analyzing obj data failed model\n";
    }
}

void Polygon::pickup_texture(char *cont)
{

    char *tmp_cont = cont;
    int count = size / 3;

    for (int i = 0; i < pp_num; i++) {

      TrianglePackPtr tri =  pp[i].tri;
      // TrianglePack の size のチェック
      int tri_size = (count < MAX_SIZE_TRIANGLE) ? count : MAX_SIZE_TRIANGLE ;
      pp[i].info.size = tri_size;

      for (int j = 0; j < tri_size; j++) {

	tmp_cont = pickup_float(tmp_cont, &(tri[j].ver1.tex_x));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].ver1.tex_y));

	tmp_cont = pickup_float(tmp_cont, &(tri[j].ver2.tex_x));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].ver2.tex_y));

	tmp_cont = pickup_float(tmp_cont, &(tri[j].ver3.tex_x));
        tmp_cont = pickup_float(tmp_cont, &(tri[j].ver3.tex_y));


	if (tmp_cont == NULL)
	  {
            cout << "Analyzing obj data failed coordinate\n";
	  }

	count -= 1;
	
      }
      
    
    }

    if (count != 0) {
          printf("miss pickup_texture size. diff size = %d\n", count);
    }



}


/*
 * surface nodeからポリゴンの情報を読み出す 再帰しない
 * 
 * get_data,get_image,makeTapestorys このファイルの外に追い出すのがよい
 */
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);
        }
    }
}

static  int
is_bmp(const char *name) {
    int  bmp = 0;

    while(*name) {
	if (bmp==0 && *name=='.') bmp = 1;
	else if (bmp==1 && (*name=='b' || *name=='B')) bmp = 2;
	else if (bmp==2 && (*name=='m' || *name=='M')) bmp = 3;
	else if (bmp==3 && (*name=='p' || *name=='P')) bmp = 4;
	else bmp = 0;
	name++;
    }
    return bmp==4;
}

#if (__LITTLE_ENDIAN__)
#define LITTLEENDIAN 1
#else
#define LITTLEENDIAN 0
#endif

static void
make_black_alpha(SDL_Surface *texture_image)
{
    int tex_w = texture_image->w;
    int tex_h = texture_image->h;
#if LITTLEENDIAN
    uint32 alpha = 0x000000ff;
#else
    uint32 alpha = 0xff000000;
#endif

    uint32 *pixels = (uint32*)texture_image->pixels;
    int i;
    for(i=0;i<tex_w*tex_h;i++) {
	uint32 pixel = pixels[i] & ~alpha;
	if (pixel==0) {
	    pixels[i] = 0;
	}
    }
}

SDL_Surface*
SceneGraph::load_decode_image(const char *file_name, const char *image_name, xmlNodePtr cur)
{
    int fd = mkstemp((char *)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);

    int alpha_black =  is_bmp(file_name);


/**
 * image を 32bit(RGBA) に変換する
 */
    SDL_Surface *texture_image = IMG_Load(image_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;
}

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;
		int nw = tex_w;
		int nh = tex_h;

                /**
                 * テクスチャの 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
                 *  8 pixcel align してない場合は、透明に 8 pixcel に拡張する
                 *  (200, 57) => 200,64 : 100,32 : 56,16: 32,8  (16,1 : 8,1 まで落すべき? 32byte)
                 *     scale = 32
                 */

		do {
		    tex_w = align(tex_w,8);
		    tex_h = align(tex_h,8);
                    all_pixel_num += tex_w * tex_h;
                    tex_w >>= 1; /* tex_w /= 2 */
                    tex_h >>= 1;
                    scale <<= 1; /* scale *= 2 */
                } while( tex_w >8 || tex_h > 8 );

                scale >>= 1;     // 必ず 1 以上になる

                tapestry = makeTapestry(manager, texture_image->w, texture_image->h,
                                        (uint32*)texture_image->pixels,
                                        all_pixel_num, scale);

                list[id].t_w = nw;
                list[id].t_h = nh;
                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.sg_hash_regist(filename, tex_id) == -1) {

        SDL_Surface *texture_image = load_decode_image(filename, image_name, cur);
	if (texture_image==0) {
	    printf("Can't load image %s\n",filename);
	    exit(0);
	}
        texture_info->texture_id = makeTapestries(manager, texture_image, tex_id);
	tex_id = texture_info->texture_id;

        if (unlink(image_name)) {
            cout << "unlink error\n";
        }
    } else {
        /**
         * 以前に Load されている Texture を共用
         */
        texture_info->texture_id = tex_id;
    }

      // こんなことすると list[] のいみあるのかなーと
      // 微妙に思う、自分で書き換えた感想 by gongo
      texture_info->t_w = list[tex_id].t_w;
      texture_info->t_h = list[tex_id].t_h;;
      texture_info->pixels_orig = list[tex_id].pixels_orig;
      texture_info->pixels = list[tex_id].pixels;
      texture_info->scale_max = list[tex_id].scale_max;
      texture_info->texture_image = list[tex_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)
{
    this->move = new_move;
}

void
SceneGraph::set_move_collision(collision_func new_collision)
{
    this->collision = new_collision;
}

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(TaskManager *manager) {

    SceneGraphPtr p = new SceneGraph(manager, this);


    return p;
}

/**
 * SceneGraph の clone
 * 予め allocate されてる領域への placement new を行う
 *
 * @param buf clone 領域
 * @return clone SceneGraph
 */

SceneGraphPtr
SceneGraph::clone(TaskManager *manager, void *buf) {
    SceneGraphPtr p = new(buf) SceneGraph(manager, 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->matrix[12] += x;
    this->matrix[13] += y;
    this->matrix[14] += z;
}

/**
 * x 軸方向への平行移動
 *
 * @param x Ttranslate in the x direction
 */
void
SceneGraph::translateX(float x)
{
    this->matrix[12] += x;
}

/**
 * y 軸方向への平行移動
 *
 * @param y Ttranslate in the y direction
 */
void
SceneGraph::translateY(float y)
{
    this->matrix[13] += y;
}

/**
 * z 軸方向への平行移動
 *
 * @param z Ttranslate in the z direction
 */
void
SceneGraph::translateZ(float z)
{
    this->matrix[14] += z;
}

void
SceneGraph::angleIt(float xangle, float yangle, float zangle)
{
    float m[16];
    float t[4] = {0,0,0,0};
    float angle[4] = {xangle, yangle, zangle, 1};
    for(int i=0;i<16;i++) m[i] = matrix[i];
    get_matrix(matrix,      angle, t, m);
}


// 今の SceneGraph の構造だと、親のスケーリングが子に繁栄される。
void
SceneGraph::scaleIt(float sx, float sy, float sz)
{

    float scale[3] = {sx, sy, sz};

    /*
     * | sx*r sx*r sx*r 0 | 
     * | sy*r sy*r sy*r 0 |
     * | sz*r sz*r sz*r 0 |
     * |  t    t    t   1 |
     */

    for(int i=0;i<3;i++) {
	for(int j=0;j<3;j++) {
	    matrix[i*4+j] = matrix[i*4+j]*scale[i]; 
        }
    }
}

/* end */