diff Renderer/Engine/viewer.cc @ 507:735f76483bb2

Reorganization..
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 12 Oct 2009 09:39:35 +0900
parents
children 8148c81d2660
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Renderer/Engine/viewer.cc	Mon Oct 12 09:39:35 2009 +0900
@@ -0,0 +1,724 @@
+#include <SDL.h>
+#include "viewer.h"
+#include "viewer_types.h"
+#include "SceneGraph.h"
+#include "SceneGraphRoot.h"
+#include "scene_graph_pack.h"
+#include "sys.h"
+#include "Func.h"
+#include "error.h"
+#include "TaskManager.h"
+#include <wchar.h>
+#include "Pad.h"
+
+static void post2runLoop(void *viewer);
+static void post2runDraw(void *viewer);
+static void post2speRendering(void *viewer);
+static void post2speDraw(void *viewer);
+// static void post2speRunLoop(void *viewer);
+//static void post2runMove(void *viewer);
+//static void post2exchange_sgroot(void *viewer);
+//static void post2speRunLoop(void *viewer);
+static void post2runMoveDrawLoop(void *viewer);
+
+/* measure for FPS (Frame Per Second) */
+int start_time;
+int this_time;
+int frames;
+
+SceneGraphRootPtr sgroot;
+//SceneGraphRootPtr sgroot_2;
+
+/* Data Pack sent to Other CPUs (ex. SPE) */
+SceneGraphPack *sgpack;
+PolygonPack *ppack;
+SpanPackPtr spackList;
+SpanPackPtr *spackList_ptr;
+
+int spackList_length;
+int spackList_length_align;
+
+/**
+ *
+ */
+
+Viewer::Viewer(int b, int w, int h, int _num)
+{
+    bpp = b;
+    width = w;
+    height = h;
+    spe_num = _num;
+}
+
+int
+Viewer::get_ticks(void)
+{
+    int time;
+    time = SDL_GetTicks();
+    return time;
+}
+
+bool
+Viewer::quit_check(void)
+{
+    SDL_Event event;
+
+    while(SDL_PollEvent(&event)) {
+        if (event.type==SDL_QUIT) {
+            return true;
+        }
+    }
+
+    Uint8 *keys=SDL_GetKeyState(NULL);
+
+    if (keys[SDLK_q] == SDL_PRESSED) {
+        return true;
+    }
+
+    return false;
+}
+
+void
+Viewer::quit(void)
+{
+    SDL_Quit();
+}
+
+void
+Viewer::swap_buffers(void)
+{
+    SDL_GL_SwapBuffers();
+}
+
+extern void node_init(TaskManager *manager);
+extern void create_cube_split(TaskManager *manager, int);
+extern void panel_init(TaskManager *manager, int bg);
+extern void universe_init(TaskManager *manager);
+extern void ieshoot_init(TaskManager *manager);
+extern void ball_bound_init(TaskManager *manager, int, int);
+extern void lcube_init(TaskManager *manager, int, int);
+extern void direction_init(TaskManager *manager);
+extern void init_position(TaskManager *manager, int, int);
+extern void vacuum_init(TaskManager *manager, int w, int h);
+extern void untitled_init(TaskManager *manager);
+extern void chain_init(TaskManager *manager, int w, int h);
+extern void chain_old_init(TaskManager *manager, int w, int h);
+extern void boss1_init(TaskManager *manager, int w, int h);
+extern void init_gaplant(TaskManager *manager, int w, int h);
+extern void vacuum_init2(TaskManager *manager, int w, int h);
+
+void
+Viewer::run_init(TaskManager *manager, const char *xml, int sg_number)
+{
+    this->manager = manager;
+
+    start_time = get_ticks();
+    this_time  = 0;
+    frames     = 0;
+
+    sgroot = new SceneGraphRoot(this->width, this->height);
+//    sgroot_2 = new SceneGraphRoot(this->width, this->height);
+    //sgroot->createFromXMLFile(xml);
+    // ここの switch は application->init(this, manager, sg_no); になるべき
+    switch (sg_number) {
+    case 0:
+    case 1:
+		create_cube_split(manager, sg_number);
+        break;
+    case 2:
+    case 3:
+    case 4:
+		panel_init(manager, sg_number);
+        break;
+    case 5:
+		universe_init(manager);
+        break;
+    case 6:
+		ieshoot_init(manager);
+        break;
+    case 7:
+		ball_bound_init(manager, this->width, this->height);
+        break;
+    case 8:
+		lcube_init(manager, this->width, this->height);
+        break;
+    case 9:
+		direction_init(manager);
+        break;
+    case 10:
+		init_position(manager, this->width, this->height);
+        break;
+    case 11:
+        //        vacuum_init(manager, this->width, this->height);
+        break;
+    case 12:
+		untitled_init(manager);
+        break;
+    case 13:
+		boss1_init(manager, this->width, this->height);
+        break;
+    case 14:
+		init_gaplant(manager, this->width, this->height);
+        break;
+    case 15:
+		vacuum_init2(manager, this->width, this->height);
+        break;
+    case 16:
+		app = new Chain();
+        app->init(manager, this->width, this->height);
+		speLoop();
+		return;
+        break;
+    case 17:
+        chain_old_init(manager, this->width, this->height);
+		break;
+    default:
+        node_init(manager);
+        break;
+    }   
+
+    mainLoop();
+}
+
+
+HTaskPtr
+Viewer::initLoop()
+{
+    HTaskPtr task_next;
+    HTaskPtr task_tex;
+
+    sgpack = (SceneGraphPack*)manager->allocate(sizeof(SceneGraphPack));
+    sgpack->init();
+    ppack  = (PolygonPack*)manager->allocate(sizeof(PolygonPack));
+
+    spackList_length = (this->height + split_screen_h - 1) / split_screen_h;
+    spackList = (SpanPack*)manager->allocate(sizeof(SpanPack)*spackList_length);
+
+    /**
+     * SPU に送る address list は 16 バイト倍数でないといけない。
+     * spackList_length*sizeof(SpanPack*) が 16 バイト倍数になるような
+     * length_align を求めている。はみ出した部分は使われない
+     * (ex) spackList_length が 13 の場合
+     *   spackList_length_align = 16;
+     *     実際に送るデータは64バイトになるのでOK
+     *     14,15,16 の部分は何も入らない。
+     */
+    spackList_length_align = (spackList_length + 3)&(~3);
+
+    /* 各 SPU が持つ、SpanPack の address list */
+    spackList_ptr =
+        (SpanPack**)manager->allocate(sizeof(SpanPack*)*spackList_length_align);
+
+    for (int i = 0; i < spackList_length; i++) {
+        spackList_ptr[i] = &spackList[i];
+    }
+
+    for (int i = 1; i <= spackList_length; i++) {
+        spackList[i-1].init(i*split_screen_h);
+    }
+
+    task_next = manager->create_task(TASK_DUMMY);
+    
+    for (int i = 0; i < spe_num; i++) {
+        task_tex = manager->create_task(TASK_INIT_TEXTURE);
+        /*
+         * ここはもう少しわかりやすい使い方がいいかもしれぬ。こんなもん?
+		 */
+        task_tex->set_cpu((CPU_TYPE)((int)SPE_0 + i));
+        task_next->wait_for(task_tex);
+        task_tex->spawn();
+    }
+
+    return task_next;
+}
+
+/* Loop って言っても1回しか実行されない */
+void
+Viewer::speLoop()
+{
+    HTaskPtr task_next = initLoop();
+    // key の情報を格納する領域を確保する (global_alloc(KEY_STATUS))
+    HTaskPtr init_key_task = manager->create_task(INIT_KEY_TASK);
+	init_key_task->set_cpu(SPE_0);
+    init_key_task->spawn();
+    
+    // SPE に送信する KEY_STATUS の領域確保
+    key_stat *key = (key_stat*)manager->allocate(sizeof(key_stat));    
+    this->keyPtr = key;
+
+    // post2runLoop は旧バージョン用なので post2speRunLoop の様なものを別につくるべき
+    //task_next->set_post(post2speRunLoop, (void*)this); // set_post(function(this->run_loop()), NULL)
+    //task_next->spawn();
+    // TASK_INIT_TEXTURE が全て終わったら DUMMY_TASK が Viewer::run_loop() を呼ぶ
+
+    /* test */
+   
+    HTaskPtr task_switch = manager->create_task(TASK_SWITCH);
+    task_switch->wait_for(task_next);
+    task_switch->set_post(post2runMoveDrawLoop, (void*)this);
+    task_switch->spawn();
+}
+
+void
+Viewer::getKey()
+{
+    Pad *pad = sgroot->getController();
+    if (pad->right.isHold()) {
+		keyPtr->right = HOLD;
+    } else if (pad->right.isPush()) {
+		keyPtr->right = PUSH;
+    } else {
+		keyPtr->right = NONE;
+    }
+    
+    if (pad->left.isHold()) {
+		keyPtr->left = HOLD;
+    } else if (pad->left.isPush()) {
+		keyPtr->left = PUSH;
+    } else {
+		keyPtr->left = NONE;
+    }
+
+    if (pad->up.isHold()) {
+		keyPtr->up = HOLD;
+    } else if (pad->up.isPush()) {
+		keyPtr->up = PUSH;
+    } else {
+		keyPtr->up = NONE;
+    }
+
+    if (pad->down.isHold()) {
+		keyPtr->down = HOLD;
+    } else if (pad->down.isPush()) {
+		keyPtr->down = PUSH;
+    } else {
+		keyPtr->down = NONE;
+    }
+
+    if (pad->circle.isHold()) {
+		keyPtr->circle = HOLD;
+    } else if (pad->circle.isPush()) {
+		keyPtr->circle = PUSH;
+    } else {
+		keyPtr->circle = NONE;
+    }
+}
+
+static void
+post2runMoveDrawLoop(void *viewer_)
+{
+    Viewer *viewer = (Viewer*)viewer_;
+    
+    // 同じ PPE 上なので sgroot(ポインタ) を add_param で送る。 
+    //HTaskPtr send_key_task = viewer->manager->create_task(SEND_KEY);
+    //send_key_task->add_param((int)sgroot);
+    // set input data -> viewer keyPtr
+    viewer->getKey();
+    HTaskPtr update_key = viewer->manager->create_task(UPDATE_KEY);
+    update_key->add_inData(viewer->keyPtr, sizeof(key_stat));
+    update_key->set_cpu(SPE_0);
+    update_key->spawn();
+    
+    /* TASK_MOVE は外から引数で取ってくるべき */
+    //HTaskPtr move_task = viewer->manager->create_task(viewer->app->move_taskid);    
+    HTaskPtr move_task = viewer->manager->create_task(TASK_MOVE);
+    //move_task->add_param(sgroot);
+
+    //HTaskPtr draw_task = viewer->manager->create_task(TASK_DRAW);
+
+    /* rendering task test */
+    HTaskPtr draw_task = viewer->manager->create_task(TASK_DUMMY);
+    HTaskPtr draw_dummy = viewer->manager->create_task(TASK_DUMMY);
+
+    HTaskPtr switch_task = viewer->manager->create_task(TASK_SWITCH);
+    viewer->draw_dummy = draw_dummy;
+    switch_task->wait_for(draw_dummy);
+    draw_task->set_post(post2speRendering, (void*)viewer);
+
+    switch_task->wait_for(move_task);
+    switch_task->wait_for(draw_task);
+    move_task->spawn();
+    draw_task->spawn();
+
+    switch_task->set_post(post2runMoveDrawLoop, (void*)viewer);
+    switch_task->spawn();
+    
+}
+
+#if 0
+static void
+post2speRunLoop(void *viewer_)
+{
+    Viewer *viewer = (Viewer *)viewer_;
+    HTaskPtr task_next = viewer->manager->create_task(TASK_DUMMY);
+    viewer->run_move(task_next);
+}
+#endif
+
+void
+Viewer::mainLoop()
+{
+    HTaskPtr task_next = initLoop();
+
+    task_next->set_post(&post2runLoop, (void *)this); // set_post(function(this->run_loop()), NULL)
+    task_next->spawn();
+}
+
+#if 0
+void
+post2runMove(void *viewer_)
+{
+    Viewer *viewer = (Viewer*)viewer_;
+    HTaskPtr task_next = viewer->manager->create_task(TASK_DUMMY);
+    viewer->run_move(task_next);
+}
+#endif
+
+
+void
+Viewer::run_move(HTaskPtr task_next)
+{
+    sgroot->updateControllerState();
+    sgroot->allExecute(width, height);
+}
+
+void
+Viewer::run_collision()
+{
+}
+
+void
+post2rendering(void *viewer_)
+{
+    Viewer *viewer = (Viewer *)viewer_;
+    HTaskPtr task_next = viewer->manager->create_task(TASK_DUMMY);
+    viewer->rendering(task_next);
+}
+
+void 
+Viewer::rendering(HTaskPtr task_next)
+{
+#if 0
+    HTaskPtr task_create_pp = manager->create_task(TASK_CREATE_PP2);
+    
+    // SceneGraph(木構造) -> PolygonPack
+
+    task_create_pp->add_param((uint32)sgroot->getDrawSceneGraph());
+    task_create_pp->add_param((uint32)ppack);
+
+    task_next->wait_for(task_create_pp);
+    
+    int range_base = spe_num;
+    // 切り上げのつもり
+    int range = (spackList_length + range_base - 1) / range_base;
+
+    for (int i = 0; i < range_base; i++) {
+        int index_start = range*i;
+        int index_end = (index_start + range >= spackList_length)
+            ? spackList_length : index_start + range;
+
+		HTaskPtr task_create_sp = manager->create_task(TASK_CREATE_SPAN);
+        task_create_sp->add_inData(ppack, sizeof(PolygonPack));
+        task_create_sp->add_inData(spackList_ptr,
+                                   sizeof(SpanPack*)*spackList_length_align);
+        task_create_sp->add_inData(&spackList[index_start], sizeof(SpanPack));
+
+        task_create_sp->add_param(index_start);
+	
+        /**
+         * ex. screen_height が 480, spenum が 6 の場合、各SPEのy担当範囲
+         *   [  1.. 80] [ 81..160] [161..240]
+         *   [241..320] [321..400] [401..480]
+         *
+         * ex. screen_height が 1080, spenum が 5 の場合、
+         *   [  1..216] [217..432] [433..648]
+         *   [649..864] [865..1080]
+         */
+        task_create_sp->add_param(index_start*split_screen_h + 1);
+        task_create_sp->add_param(index_end*split_screen_h);
+
+        task_next->wait_for(task_create_sp);
+        task_create_sp->wait_for(task_create_pp);
+
+        task_create_sp->set_cpu(SPE_ANY);
+        task_create_sp->spawn();
+    }
+
+    task_create_pp->spawn();
+#else
+    common_rendering(task_next);
+#endif
+    
+    // Barrier 同期
+    // run_draw() を呼ぶ post2runDraw
+    task_next->set_post(post2runDraw, (void*)this); // set_post(function(this->run_draw()), NULL)
+    task_next->spawn();
+
+    // TASK_CREATE_SPAN が全て終わったら DUMMY_TASK が Viewer::run_draw() を呼ぶ
+}
+
+static void
+post2runLoop(void *viewer_)
+{
+    Viewer *viewer = (Viewer*)viewer_;
+    HTaskPtr task_next = viewer->manager->create_task(TASK_DUMMY);
+    viewer->run_loop(task_next);
+
+}
+
+void
+Viewer::run_loop(HTaskPtr task_next)
+{
+    bool quit_flg;
+    quit_flg = quit_check();
+    if (quit_flg == true) {
+        this_time = get_ticks();
+        run_finish();
+        return;
+    }
+
+    clean_pixels();
+
+    for (int i = 1; i <= spackList_length; i++) {
+        spackList[i-1].reinit(i*split_screen_h);
+    }
+        
+    //run_move(task_next);
+    sgroot->updateControllerState();
+    sgroot->allExecute(width, height);
+    //sgroot->checkRemove();
+
+    // ここから下は Rendering という関数にする
+    rendering(task_next);
+}
+
+static void 
+post2runDraw(void *viewer_)
+{
+    Viewer *viewer = (Viewer*)viewer_;
+    HTaskPtr task_next = viewer->manager->create_task(TASK_DUMMY);
+    viewer->run_draw(task_next);
+
+}
+
+void
+Viewer::run_draw(HTaskPtr task_next) // 引数に post2runLoop を入れるようにする
+{
+#if 0
+    HTaskPtr task_draw;
+
+    //task_next = manager->create_task(TASK_DUMMY);
+    //task_next->set_post(post2runLoop, (void*)this);
+
+    ppack->clear();
+    for (int i = 0; i < spackList_length; i++) {
+        SpanPack *spack = &spackList[i];
+        int startx = 1;
+        int endx = split_screen_w;
+
+        int starty = spack->info.y_top - split_screen_h + 1;
+        //int endy = spack->info.y_top;
+        int rangey = (starty + split_screen_h - 1 > this->height)
+            ? this->height - starty + 1 : split_screen_h;
+
+        while (startx < this->width) {
+            if (spack->info.size > 0) {
+                // Draw SpanPack
+                task_draw = manager->create_task(TASK_DRAW_SPAN);
+                task_draw->add_inData(spack, sizeof(SpanPack));
+
+                task_draw->add_param(
+                    (uint32)&pixels[(startx-1) + this->width*(starty-1)]);
+                task_draw->add_param(this->width);
+            } else {
+		// 7.7.3 SL1 Data Cache Range Set to Zero コマンド
+		//  を使って、DMAでclearするべき... ということは、
+		// それもSPEでやる方が良い?
+                memset(&pixels[(startx-1)+this->width*(starty-1)],
+                       0, (this->width)*sizeof(int)*rangey);
+				break;
+            }
+
+            task_draw->add_param(startx);
+            task_draw->add_param(endx);
+            task_draw->add_param(rangey);
+            task_draw->set_cpu(SPE_ANY);
+            task_next->wait_for(task_draw);
+            task_draw->spawn();
+
+            startx += split_screen_w;
+            endx += split_screen_w;
+
+            if (endx > this->width) {
+                endx = this->width;
+            }
+        }
+    }
+#else    
+    common_draw(task_next);
+#endif
+
+    task_next->set_post(post2runLoop, (void*)this); // set_post(function(this->run_loop()), NULL)
+    task_next->spawn();
+    // TASK_DRAW_SPAN が全て終わったら DUMMY_TASK が Viewer::run_loop() を呼ぶ    
+
+    frames++;
+}
+
+void
+Viewer::run_finish(void)
+{
+    if (this_time != start_time) {
+        printf("%f FPS\n", (((float)frames)/(this_time-start_time))*1000.0);
+    }
+
+    delete sgroot;
+//    delete sgroot_2;
+    quit();
+}
+
+static void
+post2speRendering(void *viewer_)
+{
+    Viewer *viewer = (Viewer*)viewer_;
+    HTaskPtr task_next = viewer->manager->create_task(TASK_DUMMY);
+    viewer->spe_rendering(task_next);
+}
+
+void 
+Viewer::spe_rendering(HTaskPtr task_next)
+{
+    common_rendering(task_next);
+
+    this->draw_dummy->wait_for(task_next);
+    task_next->set_post(post2speDraw, (void*)this);
+    task_next->spawn();
+
+}
+
+static void 
+post2speDraw(void *viewer_)
+{
+    Viewer *viewer = (Viewer*)viewer_;
+    HTaskPtr task_next = viewer->manager->create_task(TASK_DUMMY);
+    viewer->spe_draw(task_next);
+}
+
+void
+Viewer::spe_draw(HTaskPtr task_next)
+{
+    common_draw(task_next);
+    
+    this->draw_dummy->wait_for(task_next);
+    task_next->spawn();
+    this->draw_dummy->spawn();
+
+    frames++;
+}
+
+void
+Viewer::common_rendering(HTaskPtr task_next)
+{
+    HTaskPtr task_create_pp = manager->create_task(TASK_CREATE_PP2);
+    
+    // SceneGraph(木構造) -> PolygonPack
+
+    task_create_pp->add_param((uint32)sgroot->getDrawSceneGraph());
+    task_create_pp->add_param((uint32)ppack);
+
+    task_next->wait_for(task_create_pp);
+    
+    int range_base = spe_num;
+    // 切り上げのつもり
+    int range = (spackList_length + range_base - 1) / range_base;
+
+    for (int i = 0; i < range_base; i++) {
+        int index_start = range*i;
+        int index_end = (index_start + range >= spackList_length)
+            ? spackList_length : index_start + range;
+
+		HTaskPtr task_create_sp = manager->create_task(TASK_CREATE_SPAN);
+        task_create_sp->add_inData(ppack, sizeof(PolygonPack));
+        task_create_sp->add_inData(spackList_ptr,
+                                   sizeof(SpanPack*)*spackList_length_align);
+        task_create_sp->add_inData(&spackList[index_start], sizeof(SpanPack));
+
+        task_create_sp->add_param(index_start);
+
+        /**
+         * ex. screen_height が 480, spenum が 6 の場合、各SPEのy担当範囲
+         *   [  1.. 80] [ 81..160] [161..240]
+         *   [241..320] [321..400] [401..480]
+         *
+         * ex. screen_height が 1080, spenum が 5 の場合、
+         *   [  1..216] [217..432] [433..648]
+         *   [649..864] [865..1080]
+         */
+        task_create_sp->add_param(index_start*split_screen_h + 1);
+        task_create_sp->add_param(index_end*split_screen_h);
+
+        task_next->wait_for(task_create_sp);
+        task_create_sp->wait_for(task_create_pp);
+
+        task_create_sp->set_cpu(SPE_ANY);
+        task_create_sp->spawn();
+    }
+
+    task_create_pp->spawn();
+}
+
+void
+Viewer::common_draw(HTaskPtr task_next)
+{
+    HTaskPtr task_draw;
+
+    //task_next = manager->create_task(TASK_DUMMY);
+    //task_next->set_post(post2runLoop, (void*)this);
+
+    ppack->clear();
+    for (int i = 0; i < spackList_length; i++) {
+        SpanPack *spack = &spackList[i];
+        int startx = 1;
+        int endx = split_screen_w;
+
+        int starty = spack->info.y_top - split_screen_h + 1;
+        //int endy = spack->info.y_top;
+        int rangey = (starty + split_screen_h - 1 > this->height)
+            ? this->height - starty + 1 : split_screen_h;
+
+        while (startx < this->width) {
+            if (spack->info.size > 0) {
+                // Draw SpanPack
+                task_draw = manager->create_task(TASK_DRAW_SPAN);
+                task_draw->add_inData(spack, sizeof(SpanPack));
+
+                task_draw->add_param(
+                    (uint32)&pixels[(startx-1) + this->width*(starty-1)]);
+                task_draw->add_param(this->width);
+            } else {
+		// 7.7.3 SL1 Data Cache Range Set to Zero コマンド
+		//  を使って、DMAでclearするべき... ということは、
+		// それもSPEでやる方が良い?
+                memset(&pixels[(startx-1)+this->width*(starty-1)],
+                       0, (this->width)*sizeof(int)*rangey);
+				break;
+            }
+
+            task_draw->add_param(startx);
+            task_draw->add_param(endx);
+            task_draw->add_param(rangey);
+            task_draw->set_cpu(SPE_ANY);
+            task_next->wait_for(task_draw);
+            task_draw->spawn();
+
+            startx += split_screen_w;
+            endx += split_screen_w;
+
+            if (endx > this->width) {
+                endx = this->width;
+            }
+        }
+    }   
+}
+
+/* end */