iT邦幫忙

2021 iThome 鐵人賽

DAY 24
0
自我挑戰組

翻車機率極高的2D平台遊戲(2D Platformer)製作系列 第 24

[Day 24] 字形渲染(Text Rendering) - 渲染文字

今日目標

  • 在視窗內渲染出"Hello, world!"

DrawText

void DrawText(const char* text, V2f pos, float sz, Color c)

這是渲染文字API的宣告,要渲染的每個字母都可以視為一小個矩形,與DrawRectangle不同的是不處理旋轉的部分(會很麻煩...再加上2D Platformer大多不會需要旋轉),第二個不同是**暫且(因為時間緊迫,想快點完成,直接用raylib的作法了)**這些文字的原點會是在左上角,然後因為正投影(Projection Matrix)我是反過來的,原點在左上角,所以找出一個字母的四個頂點座標也是反的

// 以下座標事實上劃出都會翻轉Y軸180
V2f p = { 
	pos.x + text_xoff + (CONTEXT.RenderState.default_font.chars[index].xoffset * sz),
	pos.y + (float)text_yoff + (CONTEXT.RenderState.default_font.chars[index].yoffset * sz),
};
// 右上角
V2f top_right = { p.x + CONTEXT.RenderState.default_font.chars[index].rec.w * sz, p.y + CONTEXT.RenderState.default_font.chars[index].rec.h * sz };
// 左上角
V2f top_left = { .x = p.x, .y = p.y + CONTEXT.RenderState.default_font.chars[index].rec.h * sz};
// 右下角
V2f bottom_right = { .x = p.x + CONTEXT.RenderState.default_font.chars[index].rec.w * sz, .y = p.y };
// 左下角
V2f bottom_left = { .x = p.x, .y = p.y };

再訪2D批次渲染

昨天我把ASCII Code畫在一張圖片上,作為圖集(Font Atlas)。

接著,需要對之前寫的批次渲染器做一些改造,之前主要是對不同的頂點座標做處理,這次需要加入對不同貼圖的處理,之後也會用到不同的圖集,也是用這種方法。

首先看一下改造過後的DrawCall結構

typedef struct DrawCall {
    size_t vertices_count;
    unsigned int texture_id;
} DrawCall;

多了用貼圖的ID作為依據,在每次要把頂點塞入Buffer的時候,檢查當前的texture id是不是不同的,如果是不同的,依情況利用新一個Draw Call專門處理這些頂點。

...
    // check texture id from current draw call and vertex buffer
    if (CONTEXT.RenderState.draw_calls[CONTEXT.RenderState.draw_calls_count - 1].texture_id != texture->id) {

        // check is there any shapes are waiting to draw
        if (CONTEXT.RenderState.draw_calls[CONTEXT.RenderState.draw_calls_count - 1].vertices_count > 0) {
            CONTEXT.RenderState.draw_calls_count += 1;
        }

        if (CONTEXT.RenderState.draw_calls_count >= MAX_DRAW_CALL_PER_FRAME) {
            RenderCurrentBatch();
        }

        CONTEXT.RenderState.draw_calls[CONTEXT.RenderState.draw_calls_count - 1].texture_id = texture->id;
        CONTEXT.RenderState.draw_calls[CONTEXT.RenderState.draw_calls_count - 1].vertices_count = 0;
    }
...

會先去檢查當前的Draw Call紀錄是不是已有頂點記錄在內,若有則會確定用另一個Drall Call紀錄要畫的頂點。

再來,PushVertexData多了一個Rect的參數給貼圖,根據Rect求出要渲染出的字母是在圖片中的哪一塊區域,會有四個貼圖座標,然後會每個座標分量會是範圍(0, 1),因為貼圖在座標是在[0, 1]之間。

參考

最後,今天的成果也上傳到github囉,雖然沒人會點進去看就是了O_>O


上一篇
[Day23] 字形渲染(Text Rendering) - 載入字形
下一篇
[Day 25] 雜記 - GL_TRIANGLE_STRIP與GL_TRIANGLE_FAN
系列文
翻車機率極高的2D平台遊戲(2D Platformer)製作33

尚未有邦友留言

立即登入留言