# mado: font-edit [/tools/font-edit](https://github.com/sysprog21/mado/tree/main/tools/font-edit) ``` sudo apt-get install libsdl2-dev libcairo2-dev ``` ## Flow and Map ## Console Commands `font-edit` 使用的方式需要藉由命令列(command-line)輸入,參數用於讀取 `nchars` 輸入內容。由於 `TWIN` 沒有留存完整的開發紀錄,所以這裡先從參數輸入來確認,從命令列輸入到輸出程式窗化界面的流程,理解資料流在每個 API 的背後的運作的原理。 <!-- mermaid doc https://mermaid.js.org/syntax/flowchart.html --> * `read_char()` 具體操作流程圖 ```mermaid graph TD; get_line[讀取新一行] --> cd1{包含 字元資訊}:::CDstyle; cd1 --y--> read[儲存對應字串的偏移量] --> get_line; cd1 --n--> cd2{包含 指令}:::CDstyle; cd2 --y---> cd_e{包含'e'}:::CDstyle; cd_e --y--> 結束; cd_e --n---> op[儲存命令列操作]; op --> get_line; cd2 --n---> comma[增加偏移量] --> get_line; classDef CDstyle font-size:8pt; ``` ### Console Command Types ```c typedef enum { op_move, op_line, op_curve, op_noop } op_t; ``` 在 C99 6.7.2.2 Enumeration specifiers 規範「列舉」 `enum` 宣告的內容 > The identifiers in an enumerator list are declared as constants that have type `int`. > An enumerator with = defines its enumeration constant as the value of the constant expression. If the first enumerator has no =, the value of its enumeration constant is $0$. > Each subsequent enumerator with no = defines its enumeration constant as the value of the constant expression obtained by adding $1$ to the value of the previous enumeration constant 所以 `op_t` 中的數值,各代表一個整數型態數值,自 $0$ 開始至 $3$。 ```c const int op_move = 0; const int op_line = 1; const int op_curve = 2; const int op_noop = 3; ``` `cmd_t` 為一單向鏈結串列包含一表示此命令的操作方式,以及一大小為 3 的`pt_t` 陣列。`pt_t` 為幾何型別,用於表示二維座標中一個點。 ```c typedef struct _cmd { struct _cmd *next; op_t op; pt_t pt[3]; } cmd_t; ``` `cmd_stack_t` 為一單向鏈結串列,用於實作一堆疊,包含一 `cmd_t` 單向鏈結串列指標。 ```c typedef struct _cmd_stack { struct _cmd_stack *prev; cmd_t *cmd; } cmd_stack_t; ``` ```c typedef struct _char { cmd_t *cmd; cmd_stack_t *stack; cmd_t *first; cmd_t *last; } char_t; ``` ### Functions 在 C99 5.1.2.2.1 Program startup 規範關於 `argv` > If the value of `argc` is greater than one, the strings pointed to by `argv[1]` through `argv[argc-1]` represent the program parameters. `nchars` 中繪製的字元 `!` 所需參數為 ``` /* 0x21 '!' offset 40 */ 0, 4, 42, 0, 3, 3, 0, 2, 4, /* snap_x */ -21, -15, 0, /* snap_y */ 'm', 2, -42, 'l', 2, -14, 'm', 2, -4, 'c', 1, -4, 0, -3, 0, -2, 'c', 0, -1, 1, 0, 2, 0, 'c', 3, 0, 4, -1, 4, -2, 'c', 4, -3, 3, -4, 2, -4, 'e', ``` `read_char()` 為讀取命令列參數中字元的 API,其中使用函式 `fgets` 讀取字元。 在 C99 7.19.7.2 The fgets function ```c char *fgets(char * restrict s, int n, FILE * restrict stream); ``` 7.19.6.7 The sscanf function [ISO/IEC 646](http://unicode.org/L2/L2010/10038-fcd10646-main.pdf) ## 視窗化過程 ```mermaid graph TD; 載入輸入字串 --> 初始化視窗物件 --> 輸入該字串至條樣函式 --> 輸出該條樣成字串視窗物件 --> 視窗物件載入該字串視窗物件; ``` 要將一字串繪製在一視窗介面需要以下步驟: 1. 初始化一視窗物件,該視窗物件需要給定一解析度,該解析度包含一寬度及一高度; 2. 輸入一待繪製字串請求至處理器,該待繪製字串請求包含數個繪製命令及對應每一繪製命令的至少一座標點; 3. 根據該等繪製命令及該等座標點利用一條樣函式繪製得到一對應於該待繪製字串的字串視窗物件; 4. 該視窗物件載入該字串視窗物件。 ## SDL2 API > [SDL](https://www.libsdl.org/) ### Units `` ### Methods 使用 SDL2 可以藉由 [`SDL_CreateWindow()`](https://wiki.libsdl.org/SDL2/SDL_CreateWindow),產生基本的視窗化物件 [`struct SDL_Window`](https://github.com/libsdl-org/SDL/blob/490f7af92b958c52a920fbc313c5568d3c7550d7/src/video/SDL_sysvideo.h#L43)。 ```c SDL_Window * SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags); ``` 這個視窗化物件結構體中有一指向一幾何物件的結構體指標 [`SDL_Surface *surface`](https://wiki.libsdl.org/SDL2/SDL_Surface)。 SDL_CreateRenderer SDL_CreateSurface ## Cairo API > [cairographics.org](https://www.cairographics.org/) ### Units * [`typedef struct _cairo_surface cairo_surface_t`](https://www.cairographics.org/manual/cairo-cairo-surface-t.html#cairo-surface-t) > Alternatively, if the user passes in a reference to some backing storage and asks cairo to wrap that in a `cairo_surface_t`, then the contents are not modified; for example, `cairo_image_surface_create_for_data()` and `cairo_xlib_surface_create()`. `cairo_surface_t` 是代表一圖像的具體操作物件,在 Cairo 中要繪製圖像都得經由 `cairo_surface_t` 。 * [`typedef struct _cairo cairo_t`](https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-t) > A `cairo_t` contains the current state of the rendering device, including coordinates of yet to be drawn shapes. > Cairo contexts, as `cairo_t` objects are named, are central to cairo and all drawing with cairo is always done to a `cairo_t` object. 在 Cairo 中,所有操作都是針對 `cairo_t` 展開。 要使用 `cario_surface_t` 繪製圖像,需要透過輸入一 `cairo_surface_t` 指標至 `cairo_create()` 。 * [`cairo_t * cairo_create (cairo_surface_t *target)`](https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-create) [cairo_image_surface](https://www.cairographics.org/manual/cairo-Image-Surfaces.html) ## Cairo and SDL2 Cairo 和 SDL2 大量使用物件導向設計思維,你所不知道的 C 語言:物件導向篇中有言:「[物件導向是一種態度](https://hackmd.io/@sysprog/c-oop)」,要理解 Cairo 和 SDL2 的 APIs 中是如何彼此交流資料的,必須要解析背後的設計原理。 根據 cairo 的幾何繪製方法 `cairo_image_surface_create_for_data()`,可以針對一指標指向的記憶體區塊進行繪製 ## Reference * https://www.libsdl.org/ * https://www.cairographics.org/ * [ISO/IEC 9899:1999](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf) * https://linooohon.com/blog/posts/14/211206/Character_Encoding%E5%AD%97%E5%85%83%E7%B7%A8%E7%A2%BC/Part1/ * https://github.com/tsuu32/sdl2-cairo-example * [SDL2: 從放棄到入門 by seanyih](https://hackmd.io/@seanyih/r1CxO6DH2)