view TaskManager/Test/test_render/SceneGraph.cpp @ 161:1f4c3f3238e6 fullHD_omedetou

texture の座標がマイナスになったあと、それを 0 にし忘れてた
author gongo@localhost.localdomain
date Mon, 08 Dec 2008 16:37:02 +0900
parents bbf774c57544
children dc68bc5c9e41
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"
#include "TextureHash.h"
#include "texture.h"
#include "TaskManager.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) {}

SceneGraphPtr scene_graph = NULL;
SceneGraphPtr scene_graph_viewer = NULL;

static TextureHash texture_hash;
struct texture_list list[TABLE_SIZE];

// TextureHash.cpp
extern int id_count;

SceneGraph::SceneGraph(void)
{
    init();
}

void
SceneGraph::init(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;

    texture_id = -1;
    move = no_move;
    collision = no_collision;

    frame = 0;
}

/* construct polygon from xmlNode.  */
SceneGraph::SceneGraph(xmlNodePtr surface)
{
    init();

    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);
}

SceneGraph::~SceneGraph(void)
{
    delete [] data;
}

/* XMLファイルからポリゴンを作成  */
void
SceneGraph::createFromXMLfile(char *xmlfile)
{
    xmlDocPtr doc;
    xmlNodePtr cur;
    SceneGraphPtr 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;
	    scene_graph = 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);
	    }

	    scene_graph->add_next(tmp);
	}
    }
  
    xmlFreeDoc(doc);

    //return root;
    scene_graph_viewer = root;
}

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

    /* childrenのリストの最後に加える (brother として)*/
    if (this->lastChild != NULL) {
	tmp = this->lastChild;
	tmp->brother = 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";
	    char *filename = (char *)xmlGetProp(cur, (xmlChar *)"name");
	    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);

	    /**
	     * image_name を既に Load していれば何もしない
	     */
	    int tex_id = texture_hash.hash_regist(filename);
	    if (tex_id < 0) {

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

		uint32 *tex_dest = (uint32*)manager->malloc(texture_image->w*texture_image->h*4);

		{
		    int t = 0;
		    int tex_width = texture_image->w;
		    int tex_height = texture_image->h;
		    Uint32 *tex_src = (Uint32*)texture_image->pixels;
		    
		    for (int y = 0; y < tex_height; y += TEXTURE_SPLIT_PIXEL) {
			for (int x = 0; x < tex_width; x += TEXTURE_SPLIT_PIXEL) {
			    for (int j = 0; j < TEXTURE_SPLIT_PIXEL; j++) {
				for (int i = 0; i < TEXTURE_SPLIT_PIXEL; i++) {
				    tex_dest[t++] = tex_src[(x+i) + tex_width*(y+j)];
				}
			    }
			}
		    }
		}

		list[id_count-1].t_w = texture_image->w;
		list[id_count-1].t_h = texture_image->h;
		list[id_count-1].pixels_orig = (Uint32*)texture_image->pixels;
		list[id_count-1].pixels = tex_dest;

		texture_id = id_count-1;
		texture_info.t_w = texture_image->w;
		texture_info.t_h = texture_image->h;
		texture_info.pixels_orig = (Uint32*)texture_image->pixels;
		texture_info.pixels = tex_dest;

		printf("[%s] %p\n", filename, tex_dest);

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

	    } else {
		/**
		 * 以前に Load されている Texture を共用
		 */
		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;
	    }
	}
    }
}


void
SceneGraph::delete_data(void)
{
    SceneGraphPtr n = this->next, m;

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

    if (next) {
	while (n) {
	    m = n->next;
	    delete n;
	    n = m;
	}
    }
}

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);

	t->frame++;

	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::set_move_collision(move_func new_move,
			       collision_func new_collision)
{
    this->move = new_move;
    this->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->init();
    return p;
}