view Renderer/Engine/SceneGraphRoot.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 source

#include <SDL.h>
#include <SDL_image.h>
#include <libxml/parser.h>
#include "SceneGraphRoot.h"
#include "xml.h"
#include "sys.h"
#include "TextureHash.h"
#include "texture.h"
#include "Application.h"

static int cnt = 0;
static const int SGLIST_LENGTH = 138;
static int sg_src_size = SGLIST_LENGTH ;
static int sg_src_id = -1;
static SceneGraphPtr *sg_src;


SceneGraphRoot *sgroot;

SceneGraphRoot::SceneGraphRoot(float w, float h)
{
    // SGLIST_LENGTH 決め打ちかぁ、動的生成にする場合上限決めておいた方がいいのかな
    //
    sg_src = (SceneGraphPtr*) malloc(sizeof(SceneGraphPtr)*SGLIST_LENGTH);

    camera = new Camera(w, h, this);

    iterator = new SceneGraphIterator;
    controller = create_controller();

    sg_exec_tree = NULL;
    sg_draw_tree = NULL;
    sg_available_list = NULL;
    sg_remove_list = NULL;

    sgroot = this;

    screen_w = (int)w;
    screen_h = (int)h;
    int light_num = 4;
    light_sysswitch = 0;

    for (int i = 0; i < light_num; i++) {
      light[i] = new SceneGraph;
      light[i]->xyz[0] = 0;
      light[i]->xyz[1] = 0;
      light[i]->xyz[2] = 0;

      light_switch[i] = 0;

    }

    move_finish_flag = 0;

    // TODO
    //   今はとりあえず camera を Root にしています
    //   今はそれすらもしてません
    //sg_exec_tree = camera;
}

SceneGraphRoot::~SceneGraphRoot()
{
    SceneGraphPtr p = sg_available_list;

    while (p) {
		SceneGraphPtr tmp = p->next;
		delete p;
		p = tmp;
		cnt--;
    }

    p = sg_remove_list;

    while (p) {
		SceneGraphPtr tmp = p->next;
		delete p;
		p = tmp;
		cnt--;
    }

    free(sg_src);
    delete camera;
    int light_num = 4;
    for (int i = 0; i < light_num; i++) {
      delete light[i];
    }
    delete iterator;
    delete controller;
}

/**
 * xml ファイルから生成された SceneGraph を sg_src に登録する。
 *
 * @param sg SceneGraph created by xmlfile
 */
void
SceneGraphRoot::registSceneGraph(SceneGraphPtr sg)
{
    int dup;
    if ((dup = getSgid(sg->name))>=0) { // while...
	sg_src[dup]->name = "";
	// we should remove this. but some one may use it...
    }
    if (sg_src_id+1> sg_src_size) {
	sg_src_size *= 2;
	sg_src = (SceneGraphPtr*)realloc(sg_src, sg_src_size*sizeof(SceneGraphPtr));
    }
    sg->sgid = ++sg_src_id;
    sg_src[sg->sgid] = sg;
}


void
SceneGraphRoot::addNext(SceneGraphPtr sg)
{
    SceneGraphPtr last = sg_available_list;

    if (!last) {
		sg_available_list = sg;
    } else {
		while (last->next) {
			last = last->next;
		}
		last->next = sg;
		sg->prev = last;
    }

    cnt++;
}

/* XMLファイルからポリゴンを作成  */
void
SceneGraphRoot::createFromXMLfile(TaskManager *manager, const char *xmlfile)
{
    xmlDocPtr doc;
    xmlNodePtr cur;
    SceneGraphPtr tmp;

    /* パース 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(manager, cur);	
	registSceneGraph(tmp);
    }
    xmlFreeDoc(doc);
}

void
SceneGraphRoot::createFromXMLmemory(TaskManager *manager, SceneGraph *node, char *data, int len)
{
    xmlDocPtr doc;
    xmlNodePtr cur;
    
    // size は取れるはず、テスト用に mmap したデータを使う
    /* パース DOM生成 */

    doc = xmlParseMemory(data, len);
    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)生成  */
		SceneGraphPtr original = new SceneGraph(manager, cur);	
		registSceneGraph(original);
		SceneGraphPtr clone = createSceneGraph(original->sgid);
		node->addChild(clone);
    }
    xmlFreeDoc(doc);
}

SceneGraphPtr
SceneGraphRoot::createSceneGraph(int id)
{
    SceneGraphPtr src;
    SceneGraphPtr p;

    if (id < 0 || id > sg_src_size) {
      printf("error: createSceneGraph(int id): id not found.\n");
      return NULL;
    }

    /* オリジナルの SceneGraph */
    src = sg_src[id];

    /* ユーザーにはオリジナルの clone を返す */
    p = src->clone();

    /* move, collision に sgroot を渡したいのでここで sgroot を渡しておく*/
    p->sgroot = (void *)this;

    addNext(p);

    return p;
}




SceneGraphPtr
SceneGraphRoot::createSceneGraph(const char *name)
{
    SceneGraphPtr src;
    SceneGraphPtr p;

    int id = getSgid(name);
    if (id < 0) {
      printf("error: createSceneGraph(name): name object not found.\n");
      return NULL;
    }
    
    /* オリジナルの SceneGraph */
    src = sg_src[id];

    /* ユーザーにはオリジナルの clone を返す */
    p = src->clone();
    
    /* move, collision に sgroot を渡したいのでここで sgroot を渡しておく*/
    p->sgroot = (void *)this;

    addNext(p);

    return p;
}

int
SceneGraphRoot::getSgid(const char *name)
{
    for(int i =0;i<= sg_src_id; i++) {
	if (sg_src[i] && strcmp(name,sg_src[i]->name) == 0)
	    return i;
    }
    return -1;
}

int
SceneGraphRoot::getLast()
{
    if (sg_src_id>=0)
	return sg_src[sg_src_id]->sgid;
    return -1;
}

/**
 * 何も表示しない、move,collision もしない SceneGraph を生成
 * いずれ、Transform3D 的なものに回す予定
 */
SceneGraphPtr
SceneGraphRoot::createSceneGraph()
{
    SceneGraphPtr p = new SceneGraph;

    /* move, collision に sgroot を渡したいのでここで sgroot を渡しておく*/
    p->sgroot = (void *)this;

    addNext(p);
    p->flag_drawable = 0;

    return p;
}

void
SceneGraphRoot::speExecute(int screen_w, int screen_h)
{

    SceneGraphPtr list = sg_available_list;
    // SceneGraphPtr t = sg_exec_tree;
    // SceneGraphPtr cur_parent = camera;

    // 前フレームで描画した SceneGraph は削除
    allRemove(sg_remove_list);

    // 前フレームに作られた SceneGraph は描画用に移行
    // 現フレームでの操作は以下の tree,list には適用されない
    sg_draw_tree = sg_exec_tree;
    sg_remove_list = sg_available_list;

    // 現フレームで新しく SceneGraph がコピーされるので初期化
    sg_exec_tree = NULL;
    sg_available_list = NULL;

    camera->move_execute(screen_w, screen_h);
    camera->update(screen_w, screen_h);

    camera->children = NULL;
    camera->lastChild = NULL;
    
    list->move_execute(screen_w, screen_h);
    list->collision_check(screen_w, screen_h, list);	
    
    list->frame++; 
    list = list->next;

    if(sg_exec_tree != NULL) {
		return;
    }

    /*removeのflagをもとにtreeを形成*/
    /* spe から送り返されてきた property の配列を見て生成する for()*/
    /*
    for (Property *t = (Property*)app->property[0]; is_end(t); t++){
	SceneGraphPtr s = app->scenegraph_factory(t); // SceneGraphNode を作る
	t->scenegraph = s; // property list には SceneGraphへのポインタが入っている
	app->scenegraph_connector(property[0], s); // add する
    } 
    */   
    

    // 現在、allExecute が終わった時点では
    // camera->children が User SceneGraph の root になる

    /**
     * NULL じゃなかったら、setSceneData が呼ばれてるから
     * そっちを次の Scene にする
     */

    sg_exec_tree = camera->children;
}



void
SceneGraphRoot::allExecute(int screen_w, int screen_h)
{
    SceneGraphPtr list = sg_available_list;
    SceneGraphPtr t = sg_exec_tree;
    SceneGraphPtr cur_parent = camera;

    // 前フレームで描画した SceneGraph は削除
    allRemove(sg_remove_list);

    // 前フレームに作られた SceneGraph は描画用に移行
    // 現フレームでの操作は以下の tree,list には適用されない
    sg_draw_tree = sg_exec_tree;
    sg_remove_list = sg_available_list;

    // 現フレームで新しく SceneGraph がコピーされるので初期化
    sg_exec_tree = NULL;
    sg_available_list = NULL;

    camera->move_execute(screen_w, screen_h);
    camera->update(screen_w, screen_h);

    camera->children = NULL;
    camera->lastChild = NULL;

    /*まずは全部動作させる*/
    while (list) {

        list->move_execute(screen_w, screen_h);
        list->collision_check(screen_w, screen_h, list);	
        
	list->frame++; 
        list = list->next;
    }    

    int light_num = 4;
    for (int i = 0; i < light_num; i++) {

      get_matrix(light[i]->matrix, light[i]->angle, light[i]->xyz, camera->matrix);
      
      light_vector[i*4] = 0.0f;
      light_vector[i*4+1] = 0.0f;
      light_vector[i*4+2] = 0.0f;
      light_vector[i*4+3] = 1.0f;

      ApplyMatrix(&light_vector[i*4], light[i]->matrix);
      
      light_vector[i*4] /= light_vector[i*4+2];
      light_vector[i*4+1] /= light_vector[i*4+2];

      /*SIMD演算のため*/
      light_vector[i*4+2] *= -1;
      light_vector[i*4+3] *= -1;

    }

   
    if(sg_exec_tree != NULL) {
	return;
    }

    /*removeのflagをもとにtreeを形成*/
    while (t) {
	SceneGraphPtr c = NULL;
	if (!t->isRemoved()) {
	    c = t->clone();	    
	    addNext(c);
	    cur_parent->addChild(c);
	    c->frame = t->frame;
	    /*親の回転、座標から、子の回転、座標を算出*/
	    get_matrix(c->matrix, c->angle, c->xyz, cur_parent->matrix);
	    /*法線用の行列。Cameraの行列を抜いている(Cameraのコンストラクタで、単位行列にしている)*/
	    get_matrix(c->real_matrix, c->angle, c->xyz, cur_parent->real_matrix);
	    //get_matrix(c->real_matrix, c->angle, c->xyz, camera->real_matrix);

	} 
	
	if (t->children != NULL && c != NULL) {
	    cur_parent = c;
	    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 {
                        cur_parent = cur_parent->parent;
                        t = t->parent;
		    }
		}
	    }	    
	}
    }

      

    // 現在、allExecute が終わった時点では
    // camera->children が User SceneGraph の root になる

    /**
     * NULL じゃなかったら、setSceneData が呼ばれてるから
     * そっちを次の Scene にする
     */

    sg_exec_tree = camera->children;
}

void
SceneGraphRoot::oneExecute(int screen_w, int screen_h)
{
    SceneGraphPtr list = sg_available_list;
    //SceneGraphPtr t = sg_exec_tree;
    //SceneGraphPtr cur_parent = camera;

    // 前フレームで描画した SceneGraph は削除
    allRemove(sg_remove_list);

    // 前フレームに作られた SceneGraph は描画用に移行
    // 現フレームでの操作は以下の tree,list には適用されない
    sg_draw_tree = sg_exec_tree;
    sg_remove_list = sg_available_list;

    // 現フレームで新しく SceneGraph がコピーされるので初期化
    sg_exec_tree = NULL;
    sg_available_list = NULL;

    camera->move_execute(screen_w, screen_h);
    camera->update(screen_w, screen_h);

    camera->children = NULL;
    camera->lastChild = NULL;

    /* ここから */
    list->move_execute(screen_w, screen_h);
    // ここで move_execute から実行される move_task の処理が終わるまで待ちたい
    //while(move_finish_flag == 0) {}
    //move_finish_flag = 0;

    list->create_sg_execute();
    
    list->collision_check(screen_w, screen_h, list);	
    /* ここまで exec_task にする */
    
    
    /* ここから下を exec_task の post_func に*/
    list->frame++; 
    list = list->next;


    int light_num = 4;
    for (int i = 0; i < light_num; i++) {

      get_matrix(light[i]->matrix, light[i]->angle, light[i]->xyz, camera->matrix);
      
      light_vector[i*4] = 0.0f;
      light_vector[i*4+1] = 0.0f;
      light_vector[i*4+2] = 0.0f;
      light_vector[i*4+3] = 1.0f;

      ApplyMatrix(&light_vector[i*4], light[i]->matrix);
      
      light_vector[i*4] /= light_vector[i*4+2];
      light_vector[i*4+1] /= light_vector[i*4+2];

    }
   
    if(sg_exec_tree != NULL) {
	return;
    }
}

/*
  ExecMove task の post func として呼んでやる
 */
void
SceneGraphRoot::move_finish()
{    
    list->collision_check(screen_w, screen_h, list);	

    list->frame++; 
    //list = list->next;

    int light_num = 4;
    for (int i = 0; i < light_num; i++) {

      get_matrix(light[i]->matrix, light[i]->angle, light[i]->xyz, camera->matrix);
      
      light_vector[i*4] = 0.0f;
      light_vector[i*4+1] = 0.0f;
      light_vector[i*4+2] = 0.0f;
      light_vector[i*4+3] = 1.0f;

      ApplyMatrix(&light_vector[i*4], light[i]->matrix);
      
      light_vector[i*4] /= light_vector[i*4+2];
      light_vector[i*4+1] /= light_vector[i*4+2];

      light_vector[i*4+2] *= -1;
      light_vector[i*4+3] *= -1;
    }    
    
    //sgchange->viewer->light_xyz_stock = getLightVector();
}


void
SceneGraphRoot::appTaskRegist(regist_func new_register)
{
    this->regist = new_register;
}

void
SceneGraphRoot::regist_execute()
{
    (*regist)(this);
}

void
SceneGraphRoot::allRemove(SceneGraphPtr list)
{
    SceneGraphPtr p = list;
    
    while (p) {
	SceneGraphPtr p1 = p->next;
	delete p;
	p = p1;
	cnt--;
    }
}

void
SceneGraphRoot::checkRemove()
{
    SceneGraphPtr p = sg_available_list;
    SceneGraphPtr p1;
    
    while (p) {
	p1 = p->next;
	if (p->isRemoved()) {
	    sg_exec_tree = p->realRemoveFromTree(sg_exec_tree);
	    sg_available_list = p->realRemoveFromList(sg_available_list);
	}
	delete p;
	p = p1;
    }
}

SceneGraphPtr
SceneGraphRoot::getExecuteSceneGraph()
{
    return sg_exec_tree;
}

SceneGraphPtr
SceneGraphRoot::getDrawSceneGraph()
{
    return sg_draw_tree;
}

void
SceneGraphRoot::updateControllerState()
{
    controller->check();
}

void
SceneGraphRoot::setSceneData(SceneGraphPtr sg)
{
    sg_exec_tree = sg;
}

Pad*
SceneGraphRoot::getController()
{
    return controller;
}

SceneGraphIteratorPtr
SceneGraphRoot::getIterator()
{
    iterator->set(sg_remove_list);
    return iterator;
}

SceneGraphIteratorPtr
SceneGraphRoot::getIterator(SceneGraphPtr list)
{
    iterator->set(list);
    return iterator;
}

CameraPtr
SceneGraphRoot::getCamera()
{
    return camera;
}


SceneGraphPtr
SceneGraphRoot::getLight(int id)
{

  return light[id];

}


float*
SceneGraphRoot::getLightVector()
{
  return light_vector;
}

int*
SceneGraphRoot::getLightSwitch()
{
  return light_switch;
}

int
SceneGraphRoot::getLightSysSwitch()
{
  return light_sysswitch;
}

void
SceneGraphRoot::OnLightSwitch(int id)
{
  light_switch[id] = 1;
}

void
SceneGraphRoot::OffLightSwitch(int id)
{
  light_switch[id] = 0;
}

void
SceneGraphRoot::OnLightSysSwitch()
{

  light_sysswitch = 1;

}

void
SceneGraphRoot::OffLightSysSwitch()
{

  light_sysswitch = 0;

}


void
SceneGraphRoot::set_game_task(int id, void *property, int size, PostFunction post_func)
{ 
  HTask *task = sgroot->tmanager->create_task(id);
  task->set_cpu(SPE_ANY);
  task->add_inData(property, size);
  task->add_outData(property, size);
  task->add_param((memaddr)1);
  task->set_post(post_func, (void*)property, 0);
  wait_game_task->wait_for(task);
  task->spawn();
}

void
SceneGraphRoot::set_game_task(int id, void *property, void *pad, int size, PostFunction post_func)
{
  HTask *task = sgroot->tmanager->create_task(id);
  task->set_cpu(SPE_ANY);
  task->add_inData(property, size);
  task->add_inData(pad, sizeof(Pad));
  task->add_outData(property, size);
  task->set_post(post_func, (void*)property, 0);
  wait_game_task->wait_for(task);
  task->spawn();
}

void
main_task_move(SceneGraphPtr node, void *sgroot_, int screen_w, int screen_h)
{
  int size = node->property_size;
  void *e  = node->propertyptr;
  int move = node->move_id;
  PostFunction post_func = node->post_func;

  SceneGraphRoot *sgroottmp = (SceneGraphRoot*)sgroot_;
  sgroottmp->set_game_task(move, (void*)e, size, post_func);
}

void
pad_task_move(SceneGraphPtr node, void *sgroot_, int screen_w, int screen_h)
{
  int size = node->property_size;
  void *e  = node->propertyptr;
  int move = node->move_id;
  PostFunction post_func = node->post_func;

  SceneGraphRoot *sgroottmp = (SceneGraphRoot*)sgroot_;
  void *pad = (void*)sgroottmp->getController();

  sgroottmp->set_game_task(move, (void*)e, pad, size, post_func);
}

void
SceneGraphRoot::set_move_task(SceneGraphPtr node, int move, void *property, int size, 
			      PostFunction post_func)
{
    node->move = main_task_move;
    node->post_func = post_func;
    node->move_id = move;
    node->propertyptr = property;
    node->property_size = size;
}

void
SceneGraphRoot::set_pad_task(SceneGraphPtr node, int move, void *property, int size,
			      PostFunction post_func)
{
    node->move = pad_task_move;
    node->post_func = post_func;
    node->move_id = move;
    node->propertyptr = property;
    node->property_size = size;
}

/* end */