Mercurial > hg > Members > kono > Cerium
diff Renderer/Engine/task/DrawSpan.cc @ 507:735f76483bb2
Reorganization..
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 12 Oct 2009 09:39:35 +0900 |
parents | |
children | e923249c318a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Renderer/Engine/task/DrawSpan.cc Mon Oct 12 09:39:35 2009 +0900 @@ -0,0 +1,488 @@ +#include <stdlib.h> +#include <string.h> +#include "DrawSpan.h" +#include "polygon_pack.h" +#include "texture.h" +#include "viewer_types.h" +#include "Func.h" +#include "sys.h" +#include "global_alloc.h" + +SchedDefineTask(DrawSpan); +SchedDefineTask1(DrawSpanEnd,draw_span_end); + +#define TEX_LOAD1 0 +#define TEX_LOAD2 1 +#define SPAN_PACK_LOAD 2 +#define FB_STORE 3 + +static int +draw_span_end(SchedTask *s, void *rbuf, void *wbuf) +{ + Gptr g = (Gptr)s->get_param(0); + s->dma_wait(FB_STORE); + free((void*)((int)g->linebuf*g->doneWrite)); + free(g); + return 0; +} + +/** + * テクスチャは、TEXTURE_SPLIT_PIXEL^2 のブロックに分割する + * + * +---+---+---+---+---+---+ + * | 0 | 1 | 2 | 3 | 4 | 5 | + * +---+---+---+---+---+---+ + * | | | | | |11 | + * +---+---+---+---+---+---+ + * | | | | | |17 | + * +---+---+---+---+---+---+ + * | | | | | |23 | + * +---+---+---+---+---+---+ + * | | | | | |29 | + * +---+---+---+---+---+---+ + * | | | | | |35 | + * +---+---+---+---+---+---+ + * + * 一辺を TEXTURE_SPLIT とする + * 各ブロックの数字がブロックIDとなる。 + */ + +/** + * テクスチャの座標から、 + * テクスチャのどのブロックかを求める + * + * @param[in] tx X coordinates of texture + * @param[in] tx Y coordinates of texture + * @param[in] twidth Width of texture + * @return block ID + */ +static int +getTexBlock(int tx, int ty, int twidth) +{ + int blockX, blockY; + + blockX = tx / TEXTURE_SPLIT_PIXEL; + blockY = ty / TEXTURE_SPLIT_PIXEL; + + return blockX + (twidth/TEXTURE_SPLIT_PIXEL)*blockY; +} + +/** + * block ID と、テクスチャの TOP address から + * (tx,ty) で使われるテクスチャの Tile addres を求める + * + * @param[in] tx X coordinates of texture + * @param[in] tx Y coordinates of texture + * @param[in] tw Width of texture + * @param[in] tex_addr_top (tx,ty) で使うテクスチャの先頭address + * @return block ID + */ +static memaddr +getTile(int tx, int ty, int tw, memaddr tex_addr_top) +{ + int block = getTexBlock(tx, ty, tw); + return tex_addr_top + block * TEXTURE_BLOCK_SIZE * sizeof(uint32); +} + +/** + * FrameBuffer に書き込む rgb の領域初期化 + * + * @param width Width of Buffer + * @param height Height of Buffer + * @param rgb Initial value of RGB at Buffer + * @return Buffer + */ +static int* +linebuf_init(SchedTask *smanager, int width, int height, int rgb) +{ + int *buf = (int*)smanager->allocate(sizeof(int)*width*height); + + for (int i = 0; i < width*height; i++) { + buf[i] = rgb; + } + + return buf; +} + +/** + * Z-Buffer の初期化 + * + * @param width Width of Z-Buffer + * @param height Height of Z-Buffer + * @return Z-Buffer + */ +static float* +zRow_init(SchedTask *smanager, int width, int height) +{ + float *buf = (float*)smanager->allocate(sizeof(float)*width*height); + float def = 65535.0f; + + for (int i = 0; i < width*height; i++) { + buf[i] = def; + } + + return buf; +} + + +static uint32 +get_rgb(int tx, int ty, TilePtr tile) +{ + uint32 *data = (uint32 *)tile->data; + return data[(TEXTURE_SPLIT_PIXEL)*ty+tx]; +} + + +static void +writebuffer(SchedTask *smanager, Gptr g, unsigned int display, + int buf_width, int height, int screen_width) +{ + for (int i = 0; i < height; i++) { + smanager->dma_store(&g->linebuf[i*buf_width], + display + (sizeof(int)*screen_width*i), + sizeof(int)*buf_width, FB_STORE); + } + + g->doneWrite = 1; +} + +/** + * zRow と Linebuf を更新する + * + * @param zpos 更新する pixel のZ座標 + * @param rangex このタスクが処理する描画領域の x の長さ + * @param x pixel の、描画領域内での x 座標 + * @param y 〃 の、y 座標 + * @param tex_x pixel が使用するテクスチャの、Tile (8x8) 内での x 座標 + * @param tex_y 〃 の y 座標 + * @param tex_addr テクスチャのアドレス(MainMemory) + */ +static void +updateBuffer(Gptr g, float zpos, int rangex, int x, int y, int tex_x, int tex_y, + float normal_x, float normal_y, float normal_z, TilePtr tile) +{ + + int color = get_rgb(tex_x, tex_y, tile); + /*下位4bitを抽出*/ + int alpha = color & 0x000F; + /*完全に透けているか判断*/ + int flag = (alpha != 0); + + color = infinity_light_calc(color,normal_x,normal_y,normal_z); + + g->zRow[x + (rangex*y)] = zpos*flag + g->zRow[x + (rangex*y)]*(1-flag); + g->linebuf[x + (rangex*y)] = color*flag + g->linebuf[x + (rangex*y)]*(1-flag); + +} + +/** + * 長さが 1 の Span の描画 (要するに 1 pixel) + * + * @param span Span + * @param startx 描画開始範囲 + * @param endx 描画終了範囲 + */ +static int +drawDot1(SchedTask *smanager, Gptr g, SpanPtr span, int startx, int endx, int wait_tag) +{ + int rangex = endx - startx + 1; + + float normal_x = span->normal_x; + float normal_y = span->normal_y; + float normal_z = span->normal_z; + + + /* span->x に対応する Texture の座標 (tex_xpos, tex_ypos) */ + int tex_xpos, tex_ypos; + + // span の始点に対応する Texture の座標 (tex1, tey1) + float tex = span->tex_x1; + float tey = span->tex_y1; + + // span の始点に対応する z 座標 + float zpos = span->start_z; + + /* Tile 内での座標 */ + int localx = getLocalX(span->x-1); + int localy = getLocalY(span->y-1); + + /** + * (tex_xpos, tex_ypos) の、Tile 内(上の図参照)での座標と + * そのブロックのアドレス(MainMemory) + */ + int tex_localx; + int tex_localy; + memaddr tex_addr; + + if (span->x < startx || endx < span->x) { + return -1; + } + + tex_xpos = (int)((span->tex_width-1) * tex); + tex_ypos = (int)((span->tex_height-1) * tey); + + if (zpos < g->zRow[localx + (rangex*localy)]) { + tex_addr = getTile(tex_xpos, tex_ypos, + span->tex_width, (memaddr)span->tex_addr); + tex_localx = tex_xpos % TEXTURE_SPLIT_PIXEL; + tex_localy = tex_ypos % TEXTURE_SPLIT_PIXEL; + + TilePtr tile = smanager->get_segment(tex_addr,g->tileList); + smanager->wait_segment(tile); + + updateBuffer(g, zpos, rangex, localx, localy, + tex_localx, tex_localy, + normal_x,normal_y,normal_z,tile); + } + + return -1; +} + +#if 0 +static void +drawDot2(SchedTask *smanager, SpanPtr span, int startx, int end, int js, int wait_tag) +{ + //printf("%d\n", js); +} +#endif + +/** + * 長さが 1 より大きい Span の描画 + * + * 本来の目的として、この関数(drawLine1) では + * : 既に SPE 上に Tile のある pixel だけ描画 + * : それ以外は、ここで予め DMA load しておき、 + * : drawLine2 で一気に描画する + * ってものだったんだけど、どうも上手く行かなかったので + * 今は drawLine1 で load -> wait -> rendering を全部やってます + * (rendering といっても、rendering buffer に書き込むだけで + * まだ main memory (frame buffer) に dma store してるわけではない) + * + * @param span Span + * @param startx 描画開始範囲 + * @param endx 描画終了範囲 + * @return 「span のどの位置まで rendering が終わったか」の x 座標 + */ +static int +drawLine1(SchedTask *smanager, Gptr g, SpanPtr span, int startx, int endx, int wait_tag) +{ + int x = span->x; + int rangex = endx - startx + 1; + int x_len = span->length_x; + + float normal_x = span->normal_x; + float normal_y = span->normal_y; + float normal_z = span->normal_z; + + + int js = (x < startx) ? startx - x : 0; + int je = (x + x_len > endx) ? endx - x : x_len; + + /* span->x に対応する Texture の座標 (tex_xpos, tex_ypos) */ + int tex_xpos, tex_ypos; + + // span の始点に対応する座標 (tex1, tey1) + float tex1 = span->tex_x1; + float tey1 = span->tex_y1; + + // span の終点に対応する座標 (tex2, tey2) + float tex2 = span->tex_x2; + float tey2 = span->tex_y2; + + // span の始点、終点に対応する z 座標 + float zpos1 = span->start_z; + float zpos2 = span->end_z; + + // Tile 内での座標 + int localx, localy = getLocalY(span->y-1); + + int ret = je+1; + + //for (int j = js; j <= je; j++) { + for (int j = je; j >= js; j--) { + float tex_x, tex_y, tex_z; + + localx = getLocalX(x-1+j); + + tex_z = zpos1*(x_len-1-j)/(x_len-1) + zpos2*j/(x_len-1); + + tex_x = tex1*(x_len-1-j)/(x_len-1) + tex2*j/(x_len-1); + tex_y = tey1*(x_len-1-j)/(x_len-1) + tey2*j/(x_len-1); + if (tex_x > 1) tex_x = 1; + if (tex_x < 0) tex_x = 0; + if (tex_y > 1) tex_y = 1; + if (tex_y < 0) tex_y = 0; + tex_xpos = (int)((span->tex_width-1) * tex_x); + tex_ypos = (int)((span->tex_height-1) * tex_y); + + if (tex_z < g->zRow[localx + (rangex*localy)]) { + // (tex_xpos, tex_ypos) の、Tile 内(上の図参照)での座標と + // そのブロックのアドレス(MainMemory) + memaddr tex_addr; + int tex_localx; + int tex_localy; + + tex_addr = getTile(tex_xpos, tex_ypos, + span->tex_width, (memaddr)span->tex_addr); + tex_localx = tex_xpos % TEXTURE_SPLIT_PIXEL; + tex_localy = tex_ypos % TEXTURE_SPLIT_PIXEL; + TilePtr tile = smanager->get_segment(tex_addr,g->tileList); + smanager->wait_segment(tile); + + updateBuffer(g, tex_z, rangex, localx, localy, + tex_localx, tex_localy, + normal_x, normal_y, normal_z, tile); + } + } + + return ret; +} + +static int +infinity_light_calc(int color,float normal_x, float normal_y, float normal_z) +{ + unsigned char rgb[4]; + int light_rgb; + int flag; + float normal_vector[4] = {normal_x,normal_y,normal_z,0}; + // 光のベクトル,きめうちしちゃった。どうにかする + float light_vector[4] = {0,0,-1,0}; + float inner_product; + + // 引数で受け取った color の rgb 情報の抜き出し + rgb[0] = (color & 0xff000000) >> 24; + rgb[1] = (color & 0x00ff0000) >> 16; + rgb[2] = (color & 0x0000ff00) >> 8; + rgb[3] = (color & 0x000000ff); + + // 法線ベクトルと光源ベクトルとの内積をとる + inner_product = innerProduct(normal_vector,light_vector); + // 内積がマイナスの場合は色がない。 + flag = (inner_product > 0); + + // 内積を rgb にかけていく + rgb[0] = (unsigned char)(rgb[0]*inner_product*flag); + rgb[1] = (unsigned char)(rgb[1]*inner_product*flag); + rgb[2] = (unsigned char)(rgb[2]*inner_product*flag); + + //計算した rgb を light_rgb にまとめる。 + light_rgb = (rgb[0] << 24) + (rgb[1] << 16) + (rgb[2] << 8) + (rgb[3]); + + return light_rgb; +} + + +static int +run(SchedTask *smanager, void *rbuf, void *wbuf) +{ + Gptr g = (Gptr)smanager->allocate(sizeof(G)); + + SpanPackPtr spack = (SpanPackPtr)smanager->get_input(0); + SpanPackPtr next_spack = (SpanPackPtr)smanager->allocate(sizeof(SpanPack)); + SpanPackPtr free_spack = next_spack; // next_spack の free() 用 + Span *span; + + Span nop_span; + nop_span.length_x = 1; + + int (*drawFunc1[2])(SchedTask *, Gptr, SpanPtr, int, int, int) = { + &drawDot1, &drawLine1 + }; + + uint32 display = smanager->get_param(0); + int screen_width = smanager->get_param(1); + int rangex_start = smanager->get_param(2); + int rangex_end = smanager->get_param(3); + + // このタスクが担当する x の範囲 + int rangex = rangex_end - rangex_start + 1; + + // y の範囲 + int rangey = smanager->get_param(4); + g->tileList = (TileListPtr)smanager->global_get(GLOBAL_TILE_LIST); + + g->zRow = zRow_init(smanager, rangex, rangey); + //linebuf = linebuf_init(rangex, rangey, 0x00ffffff); + g->linebuf = linebuf_init(smanager, rangex, rangey, 0); + + g->doneWrite = 0; + + int tl_tag[2] = {TEX_LOAD1, TEX_LOAD2}; + int tl_tag_flg1 = 0; + int tl_tag_flg2 = 1; + + do { + /** + * SpanPack->next が存在する場合、 + * 現在の SpanPack を処理してる間に + * 次の SpanPack の DMA 転送を行う + */ + if (spack->next != NULL) { + smanager->dma_load(next_spack, (uint32)spack->next, + sizeof(SpanPack), SPAN_PACK_LOAD); + } else { + next_spack = NULL; + } + + SpanPtr resume_span = &nop_span; + int resume_span_x = 0; + + for (int t = 0; t < spack->info.size; t++) { + SpanPtr next_span; + int next_span_x; + + span = &spack->span[t]; + + /** + * span の長さによって、drawLine か drawDot を選択している + */ + next_span_x + = (*drawFunc1[(span->length_x != 1)])( + smanager, g, + span, rangex_start, rangex_end, tl_tag[tl_tag_flg1]); + next_span = span; + + resume_span = next_span; + resume_span_x = next_span_x; + + //smanager->dma_wait(tl_tag[tl_tag_flg1]); + + tl_tag_flg1 ^= 1; + tl_tag_flg2 ^= 1; + } + + // 現在 drawLine2、drawDot2 は機能してないので + //(this->*drawFunc2[(resume_span->length_x != 1)])( + //resume_span, rangex_start, rangex_end, resume_span_x, + //tl_tag[tl_tag_flg1]); + + smanager->dma_wait(SPAN_PACK_LOAD); + + SpanPackPtr tmp_spack = spack; + spack = next_spack; + next_spack = tmp_spack; + } while (spack); + + writebuffer(smanager, g, display, rangex, rangey, screen_width); + + // linebuf は、writebuffer() の dma_store を wait する + // DrawSpan::~DrawSpan() 内で free する。 + //free(linebuf); + free(g->zRow); + +//FINISH: + /** + * goto FINISH; の時は reboot なので + * linebuf, zRow は free() しない + */ + + free(free_spack); + + TaskPtr nextTask = smanager->create_task(TASK_DRAW_SPAN_END); + nextTask->add_param((int)g); + smanager->wait_task(nextTask); + + return 0; +} + +/* end */