view TaskManager/Test/test_render/SceneGraph.cpp @ 139:c948f4ebde62

fix
author gongo@charles.cr.ie.u-ryukyu.ac.jp
date Fri, 28 Nov 2008 13:51:54 +0900
parents 3fd24be89d02
children 861271089c43
line wrap: on
line source

#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"

using namespace std;

extern int decode(char *cont, FILE *outfile);

static void
no_move(SceneGraphPtr self, int screen_w, int screen_h) {}

static void
no_collision(SceneGraphPtr self, int screen_w, int screen_h,
	     SceneGraphPtr tree) {}

SceneGraph::SceneGraph(void)
{
    next = 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;

    move = no_move;
    collision = no_collision;
}


/* construct polygon from xmlNode.  */
SceneGraph::SceneGraph(xmlNodePtr surface)
{
#if 1
    next = NULL;
    last = NULL;
    parent = NULL;
    brother = NULL;
    children = NULL;
    lastChild = NULL;
    move = no_move;
    collision = no_collision;
#else
    // こうしたいんだけどなー
    this->SceneGraph();
#endif

    size = atoi((char *)xmlGetProp(surface,(xmlChar *)"size"));
    name = (char *)xmlGetProp(surface,(xmlChar *)"name");
    parent_name = (char *)xmlGetProp(surface,(xmlChar *)"parent");

    data = new float[size*3*3];

    get_data(surface->children);
}


/* XMLファイルからポリゴンを作成  */
SceneGraph*
SceneGraph::createFromXMLfile(char *xmlfile)
{
    xmlDocPtr doc;
    xmlNodePtr cur;
    SceneGraph *root = NULL, *tmp, *parent;

    /* パース DOM生成 */
    doc = xmlParseFile(xmlfile);
    cur = xmlDocGetRootElement(doc);

    /* ??  */
    xmlStrcmp(cur->name,(xmlChar*)"OBJECT-3D");

    /* XMLのノードを一つずつ解析  */
    for (cur=cur->children; cur; cur=cur->next) {
	/* 扱うのはsurfaceオンリー  */
	if (xmlStrcmp(cur->name,(xmlChar*)"surface") != 0) {
	    continue;
	}

	/* ポリゴン(SceneGraph)生成  */
	tmp = new SceneGraph(cur);
	if ( tmp->parent_name==NULL || 0==strcmp(tmp->parent_name, "NULL")) {
	    /* このsurfaceがroot  */
	    root = tmp;
	} else {
	    /* 親はこのsurfaceより前に定義されているものとする (していい?)  */
	    //  ここで parent_name を用いるのは間違っていて、
	    //   *cur->properties->children から探すべきらしい kono
	    parent = root->searchSceneGraph(tmp->parent_name);
	    if (parent==NULL) {
		fprintf(stderr, "[%s] No such parent %s\n",
			tmp->name, tmp->parent_name);
		root->addChild(tmp);
	    } else {
		parent->addChild(tmp);
	    }
	    root->add_next(tmp);
	}
    }
  
    xmlFreeDoc(doc);
    return root;
}

/* 子供を追加  */
SceneGraph*
SceneGraph::addChild(SceneGraph *child)
{
    SceneGraph *tmp;

    /* childrenのリストの最後に加える */
    if (this->lastChild != NULL) {
	tmp = this->lastChild;
	tmp->children = child;
    }

    this->lastChild = child;

    if (this->children == NULL) {
	this->children = child;
    }

    child->parent = this;

    return child;
}

/* 兄弟を追加  */
SceneGraph*
SceneGraph::addBrother(SceneGraph *bro)
{
    SceneGraphPtr sg = this->brother;

    if (sg != NULL) {
	while (sg->brother) {
	    sg = sg->brother;
	}
	sg->brother = bro;
    } else {
	this->brother = bro;
    }

    if (this->parent) {
	parent->addChild(bro);
    }

    return bro;
}

/* thisの子や子孫にnameのものが存在すればそいつを返す なければNULL.  */
SceneGraph*
SceneGraph::searchSceneGraph(char *name)
{
    SceneGraph* tmp;
    SceneGraph* 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(void)
{
    SceneGraph *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(void)
{
    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(xmlNodePtr cur)
{
    char *cont;
    //char *image_name;

    for(;cur;cur=cur->next)
    {
	if(!xmlStrcmp(cur->name,(xmlChar*)"coordinate"))
        {
	    cont = (char *)xmlNodeGetContent(cur);
	    pickup_coordinate(cont);
        }
	else if(!xmlStrcmp(cur->name,(xmlChar*)"normal"))
        {
	    cont = (char *)xmlNodeGetContent(cur);
	    pickup_normal(cont);
        }
	else if(!xmlStrcmp(cur->name,(xmlChar*)"model"))
        {
	    cont = (char *)xmlNodeGetContent(cur);
	    pickup_model(cont);
        }
	else if(!xmlStrcmp(cur->name,(xmlChar*)"texture"))
        {
	    cont = (char *)xmlNodeGetContent(cur);
	    pickup_texture(cont);
	}
	else if(!xmlStrcmp(cur->name,(xmlChar*)"image"))
        {
	    char image_name[20] = "/tmp/image_XXXXXX";
	    int fd = mkstemp(image_name);
	    FILE *outfile = fdopen(fd, "wb");
	    if(NULL == outfile)
	    {
		cout << "error open file\n";
	    }
	    cont = (char *)xmlNodeGetContent(cur);
	    //decode(cont, image_name);
	    decode(cont, outfile);
	    fclose(outfile);

	    texture_image = IMG_Load(image_name);

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

	    //load_texture(image_name);
	    if(unlink(image_name))
	    {
		cout << "unlink error\n";
	    }
        }
    }
}


void
SceneGraph::delete_data(void)
{
    SceneGraph *n,*m;

    n = this;
    delete [] n->data;

    if (next)
    {
	for(n = this->next; n; n=m)
	{
	    m = n->next;
	    delete [] n->data;
	    delete n;
	}
    }
}

void
SceneGraph::move_execute(int w, int h)
{
    (*move)(this, w, h);
}

void
SceneGraph::collision_check(int w, int h, SceneGraph *tree)
{
    (*collision)(this, w, h, tree);
}

void
SceneGraph::all_execute(int screen_w, int screen_h)
{
    SceneGraphPtr top = this;
    SceneGraphPtr t = top;

    while (t) {
	t->move_execute(screen_w, screen_h);
	t->collision_check(screen_w, screen_h, top);

	if (t->parent != NULL) {
	    get_matrix(t->matrix, t->angle, t->xyz, t->parent->matrix);
	} else {
	    get_matrix(t->matrix, t->angle, t->xyz, NULL);
	}

	if (t->children != NULL) {
	    t = t->children;
	} else if (t->brother != NULL) {
	    t = t->brother;
	} else {
	    while (t) {
		if (t->brother != NULL) {
		    t = t->brother;
		    break;
		} else {
		    if (t->parent == NULL) {
			t = NULL;
			break;
		    } else {
			t = t->parent;
		    }
		}
	    }
	}
    }
}

void
SceneGraph::set_move_collision(SceneGraphPtr node, move_func new_move,
			       collision_func new_collision)
{
    node->move = new_move;
    node->collision = new_collision;
}

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*
SceneGraph::clone(void) {
    SceneGraphPtr p = new SceneGraph;
    memcpy(p, this, sizeof(SceneGraph));


    // どっかで関数にまとめるか
    p->next = NULL;
    p->last = NULL;

    p->parent = NULL;
    p->brother = NULL;
    p->children = NULL;
    p->lastChild = NULL;
    p->move = no_move;
    p->collision = no_collision;

    p->stack_xyz[0] = 0.0f;
    p->stack_xyz[2] = 0.0f;
    p->stack_xyz[1] = 0.0f;
    p->stack_angle[0] = 0.0f;
    p->stack_angle[1] = 0.0f;
    p->stack_angle[2] = 0.0f;
    
    return p;
}