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 };
昨天我把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]之間。