#help_index "TextBase Layer;Char/TextBase Layer"
#help_file "::/Doc/TextBase"

asm {
//************************************
_TEXT_CHAR::
//Bool TextChar(CTask *task,Bool allow_border=FALSE,I64 x,I64 y,I64 d);
//Must be called 60fps in Fs->draw_it() callback.
                PUSH        RBP
                MOV         RBP, RSP
                MOV         RCX, U64 SF_ARG1[RBP]
                MOV         RBX, U64 CTask.scroll_x[RCX]
                SAR         RBX, 3
                ADD         RBX, U64 SF_ARG3[RBP]
                MOV         RAX, U64 CTask.scroll_y[RCX]
                SAR         RAX, 3
                ADD         RAX, U64 SF_ARG4[RBP]

                TEST        U8 SF_ARG2[RBP], 0xFF
                JNZ         @@10

//Border not allowed
                TEST        RBX, RBX                //Check X
                JS          @@05
                ADD         RBX, U64 CTask.win_left[RCX]
                CMP         RBX, U64 CTask.win_right[RCX]
                JG          @@05
                TEST        RBX, RBX
                JS          @@05
                CMP         RBX, TEXT_COLS
                JGE         @@05
                TEST        RAX, RAX                //Check Y
                JS          @@05
                ADD         RAX, U64 CTask.win_top[RCX]
                CMP         RAX, U64 CTask.win_bottom[RCX]
                JG          @@05
                TEST        RAX, RAX
                JS          @@05
                CMP         RAX, TEXT_ROWS
                JGE         @@05
                JMP         @@15

@@05:           XOR         RAX, RAX                //return FALSE
                POP         RBP
                RET1        40

//Border allowed
@@10:           MOV         RDX, -1                 //Check X
                CMP         RBX, RDX
                JL          @@05
                ADD         RBX, U64 CTask.win_left[RCX]
                MOV         RDX, U64 CTask.win_right[RCX]
                INC         RDX
                CMP         RBX, RDX
                JG          @@05
                TEST        RBX, RBX
                JS          @@05
                CMP         RBX, TEXT_COLS
                JGE         @@05
                MOV         RDX, -1                 //Check Y
                CMP         RAX, RDX
                JL          @@05
                ADD         RAX, U64 CTask.win_top[RCX]
                MOV         RDX, U64 CTask.win_bottom[RCX]
                INC         RDX
                CMP         RAX, RDX
                JG          @@05
                TEST        RAX, RAX
                JS          @@05
                CMP         RAX, TEXT_ROWS
                JGE         @@05

@@15:           IMUL2       RAX, TEXT_COLS
                ADD         RBX, RAX
                SHL         RBX, 2
                ADD         RBX, U64 [&gr.text_base]
                MOV         RAX, U64 SF_ARG5[RBP]
                MOV         U32 [RBX], EAX

                MOV         RAX, TRUE
                POP         RBP
                RET1        40
//************************************
_TEXT_LEN_STR::
//Bool TextLenStr(CTask *task,I64 x,I64 y,I64 len,I64 attr,U8 *s)
//Must be called 60fps in Fs->draw_it() callback.
                PUSH        RBP
                MOV         RBP, RSP
                PUSH        RSI
                PUSH        RDI
                MOV         RBX, U64 SF_ARG1[RBP]
                MOV         RSI, U64 SF_ARG6[RBP]
                MOV         RDI, U64 CTask.scroll_x[RBX]
                SAR         RDI, 3
                ADD         RDI, U64 SF_ARG2[RBP]
                MOV         RCX, U64 SF_ARG4[RBP]

                TEST        RDI, RDI
                JNS         @@05
                ADD         RCX, RDI
                SUB         RSI, RDI
                XOR         RDI, RDI
@@05:           ADD         RDI, U64 CTask.win_left[RBX]
                MOV         RDX, RCX
                ADD         RDX, RDI
                DEC         RDX
                CMP         RDX, U64 CTask.win_right[RBX]
                JLE         @@10
                MOV         RAX, RDX
                SUB         RAX, U64 CTask.win_right[RBX]
                SUB         RDX, RAX
                SUB         RCX, RAX
@@10:           TEST        RDI, RDI
                JNS         @@15
                ADD         RCX, RDI
                SUB         RSI, RDI
                XOR         RDI, RDI
@@15:           INC         RDX
                SUB         RDX, TEXT_COLS
                JLE         @@20
                SUB         RCX, RDX
@@20:           CMP         RCX, 1
                JL          @@30

                MOV         RAX, U64 CTask.scroll_y[RBX]
                SAR         RAX, 3
                ADD         RAX, U64 SF_ARG3[RBP]
                TEST        RAX, RAX
                JS          @@30
                ADD         RAX, U64 CTask.win_top[RBX]
                CMP         RAX, U64 CTask.win_bottom[RBX]
                JG          @@30
                TEST        RAX, RAX
                JS          @@30
                CMP         RAX, TEXT_ROWS
                JGE         @@30

                IMUL2       RAX, TEXT_COLS
                ADD         RDI, RAX
                SHL         RDI, 2
                ADD         RDI, U64 [&gr.text_base]
                MOV         RAX, U64 SF_ARG5[RBP]
@@25:           LODSB
                STOSD
                DEC         RCX
                JNZ         @@25

                POP         RDI
                POP         RSI
                MOV         RAX, TRUE
                POP         RBP
                RET1        48

@@30:           POP         RDI
                POP         RSI
                XOR         RAX, RAX
                POP         RBP
                RET1        48
//************************************
_TEXT_LEN_ATTR_STR::
//Bool TextLenAttrStr(CTask *task,I64 x,I64 y,I64 len,U32 *_attr)
//Must be called 60fps in Fs->draw_it() callback.
                PUSH        RBP
                MOV         RBP, RSP
                PUSH        RSI
                PUSH        RDI
                MOV         RBX, U64 SF_ARG1[RBP]
                MOV         RSI, U64 SF_ARG5[RBP]
                MOV         RDI, U64 CTask.scroll_x[RBX]
                SAR         RDI, 3
                ADD         RDI, U64 SF_ARG2[RBP]
                MOV         RCX, U64 SF_ARG4[RBP]

                TEST        RDI, RDI
                JNS         @@05
                ADD         RCX, RDI
                SHL         RDI, 2
                SUB         RSI, RDI
                XOR         RDI, RDI
@@05:           ADD         RDI, U64 CTask.win_left[RBX]
                MOV         RDX, RCX
                ADD         RDX, RDI
                DEC         RDX
                CMP         RDX, U64 CTask.win_right[RBX]
                JLE         @@10
                MOV         RAX, RDX
                SUB         RAX, U64 CTask.win_right[RBX]
                SUB         RDX, RAX
                SUB         RCX, RAX
@@10:           TEST        RDI, RDI
                JNS         @@15
                ADD         RCX, RDI
                SHL         RDI, 2
                SUB         RSI, RDI
                XOR         RDI, RDI
@@15:           INC         RDX
                SUB         RDX, TEXT_COLS
                JLE         @@20
                SUB         RCX, RDX
@@20:           CMP         RCX, 1
                JL          @@30

                MOV         RAX, U64 CTask.scroll_y[RBX]
                SAR         RAX, 3
                ADD         RAX, U64 SF_ARG3[RBP]
                TEST        RAX, RAX
                JS          @@30
                ADD         RAX, U64 CTask.win_top[RBX]
                CMP         RAX, U64 CTask.win_bottom[RBX]
                JG          @@30
                TEST        RAX, RAX
                JS          @@30
                CMP         RAX, TEXT_ROWS
                JGE         @@30

                IMUL2       RAX, TEXT_COLS
                ADD         RDI, RAX
                SHL         RDI, 2
                ADD         RDI, U64 [&gr.text_base]
@@25:           MOVSD
                DEC         RCX
                JNZ         @@25

                POP         RDI
                POP         RSI
                MOV         RAX, TRUE
                POP         RBP
                RET1        40

@@30:           POP         RDI
                POP         RSI
                XOR         RAX, RAX
                POP         RBP
                RET1        40
//************************************
_TEXT_LEN_ATTR:://Bool TextLenAttr(CTask *task,I64 x,I64 y,I64 len,I64 attr)
//Must be called 60fps in Fs->draw_it() callback.
                PUSH        RBP
                MOV         RBP, RSP
                PUSH        RSI
                PUSH        RDI
                MOV         RBX, U64 SF_ARG1[RBP]
                MOV         RDI, U64 CTask.scroll_x[RBX]
                SAR         RDI, 3
                ADD         RDI, U64 SF_ARG2[RBP]
                MOV         RCX, U64 SF_ARG4[RBP]

                TEST        RDI, RDI
                JNS         @@05
                ADD         RCX, RDI
                XOR         RDI, RDI
@@05:           ADD         RDI, U64 CTask.win_left[RBX]
                MOV         RDX, RCX
                ADD         RDX, RDI
                DEC         RDX
                CMP         RDX, U64 CTask.win_right[RBX]
                JLE         @@10
                MOV         RAX, RDX
                SUB         RAX, U64 CTask.win_right[RBX]
                SUB         RDX, RAX
                SUB         RCX, RAX
@@10:           TEST        RDI, RDI
                JNS         @@15
                ADD         RCX, RDI
                XOR         RDI, RDI
@@15:           INC         RDX
                SUB         RDX, TEXT_COLS
                JLE         @@20
                SUB         RCX, RDX
@@20:           CMP         RCX, 1
                JL          @@35

                MOV         RAX, U64 CTask.scroll_y[RBX]
                SAR         RAX, 3
                ADD         RAX, U64 SF_ARG3[RBP]
                TEST        RAX, RAX
                JS          @@35
                ADD         RAX, U64 CTask.win_top[RBX]
                CMP         RAX, U64 CTask.win_bottom[RBX]
                JG          @@35
                TEST        RAX, RAX
                JS          @@35
                CMP         RAX, TEXT_ROWS
                JGE         @@35

                IMUL2       RAX, TEXT_COLS
                ADD         RDI, RAX
                SHL         RDI, 2
                ADD         RDI, U64 [&gr.text_base]
                MOV         RBX, U64 SF_ARG5[RBP]
                MOV         RSI, RDI
@@25:           LODSD
                TEST        AL, AL
                JNZ         @@30
                MOV         RAX, RBX
                STOSD
                DEC         RCX
                JNZ         @@25

@@30:           POP         RDI
                POP         RSI
                MOV         RAX, TRUE
                POP         RBP
                RET1        40

@@35:           POP         RDI
                POP         RSI
                XOR         RAX, RAX
                POP         RBP
                RET1        40
}
public _extern _TEXT_CHAR Bool TextChar(CTask *task, Bool allow_border=FALSE, I64 x, I64 y, I64 d);
//Plot char. 60fps in Fs->draw_it() callback.

public _extern _TEXT_LEN_STR Bool TextLenStr(CTask *task, I64 x, I64 y, I64 len, I64 attr, U8 *s);
//Plot str with len.  60fps in Fs->draw_it() callback.

public _extern _TEXT_LEN_ATTR_STR Bool TextLenAttrStr(CTask *task, I64 x, I64 y, I64 len, U32 *_attr);
//Plot attr str with len.   60fps in Fs->draw_it() callback.

public _extern _TEXT_LEN_ATTR Bool TextLenAttr(CTask *task, I64 x, I64 y, I64 len, I64 attr);
//Plot attrs with len.  60fps in Fs->draw_it() callback.

public U0 TextPrint(CTask *task, I64 x, I64 y, I64 attr, U8 *format, ...)
{//Plot chars. 60fps in Fs->draw_it() callback.
//You probably want GrPrint() or just Print().
    U8 *buf = StrPrintJoin(NULL, format, argc, argv);

    TextLenStr(task, x, y, StrLen(buf), attr<<8, buf);
    Free(buf);
}

public U0 TextBorder(CTask *task=NULL, I64 l, I64 r, I64 t, I64 b, I64 attr, Bool solid)
{//Plot border square. 60fps in Fs->draw_it() callback.
//Draws window borders or DolDoc text button borders.
    //Set task=sys_winmgr_task for no clipping.
    I64 i;

    if (!task)
        task = Fs;

    attr <<= 8;
    TextChar(task,, l - 1, t - 1, text.border_chars[6  + solid] + attr);
    TextChar(task,, r + 1, t - 1, text.border_chars[8  + solid] + attr);
    TextChar(task,, l - 1, b + 1, text.border_chars[10 + solid] + attr);
    TextChar(task,, r + 1, b + 1, text.border_chars[12 + solid] + attr);
    for (i = l; i <= r; i++)
    {
        TextChar(task,, i, t - 1, text.border_chars[2 + solid] + attr);
        TextChar(task,, i, b + 1, text.border_chars[2 + solid] + attr);
    }
    for (i = t; i <= b; i++)
    {
        TextChar(task,, l - 1, i, text.border_chars[4 + solid] + attr);
        TextChar(task,, r + 1, i, text.border_chars[4 + solid] + attr);
    }
}

public U0 TextRect(I64 l, I64 r, I64 t, I64 b, I64 d)
{//Fill text rect. 60fps in Fs->draw_it() callback.
    I64 y, w;

    if (l > r || t > b)
        return;
    if (t < 0)
        t = 0;
    if (b >= TEXT_ROWS)
        b = TEXT_ROWS - 1;
    if (l < 0)
        l = 0;
    if (r >= TEXT_COLS)
        r = TEXT_COLS - 1;

    if (w = r - l + 1)
        for (y = t; y <= b; y++)
            MemSetU32(gr.text_base(U8 *) + (y * TEXT_COLS + l) * sizeof(U32), d, w);
}